2016-08-08 21:49:09 +02:00
|
|
|
// Copyright (c) 2013-2016 The btcsuite developers
|
2015-12-01 19:44:58 +01:00
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
2013-08-21 16:37:30 +02:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
package keystore
|
2013-08-21 16:37:30 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/aes"
|
|
|
|
"crypto/cipher"
|
2013-09-03 06:10:32 +02:00
|
|
|
"crypto/rand"
|
2013-08-21 16:37:30 +02:00
|
|
|
"crypto/sha512"
|
|
|
|
"encoding/binary"
|
2013-11-20 16:17:49 +01:00
|
|
|
"encoding/hex"
|
2013-08-21 16:37:30 +02:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2014-05-23 04:16:50 +02:00
|
|
|
"io"
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
"io/ioutil"
|
2014-05-23 04:16:50 +02:00
|
|
|
"math/big"
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sync"
|
2014-05-23 04:16:50 +02:00
|
|
|
"time"
|
|
|
|
|
2016-05-05 21:04:36 +02:00
|
|
|
"golang.org/x/crypto/ripemd160"
|
|
|
|
|
2015-02-06 17:43:23 +01:00
|
|
|
"github.com/btcsuite/btcd/btcec"
|
2015-02-06 06:51:37 +01:00
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
2016-08-08 21:49:09 +02:00
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
2015-01-30 19:31:29 +01:00
|
|
|
"github.com/btcsuite/btcd/txscript"
|
2015-02-05 22:41:38 +01:00
|
|
|
"github.com/btcsuite/btcd/wire"
|
2015-01-15 17:48:58 +01:00
|
|
|
"github.com/btcsuite/btcutil"
|
2015-05-27 16:09:22 +02:00
|
|
|
"github.com/btcsuite/btcwallet/internal/legacy/rename"
|
2013-08-21 16:37:30 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2014-10-14 00:57:57 +02:00
|
|
|
Filename = "wallet.bin"
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
// Length in bytes of KDF output.
|
|
|
|
kdfOutputBytes = 32
|
|
|
|
)
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
const (
|
|
|
|
defaultKdfComputeTime = 0.25
|
|
|
|
defaultKdfMaxMem = 32 * 1024 * 1024
|
|
|
|
)
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Possible errors when dealing with key stores.
|
2013-08-21 16:37:30 +02:00
|
|
|
var (
|
2014-07-08 20:17:24 +02:00
|
|
|
ErrAddressNotFound = errors.New("address not found")
|
|
|
|
ErrAlreadyEncrypted = errors.New("private key is already encrypted")
|
|
|
|
ErrChecksumMismatch = errors.New("checksum mismatch")
|
|
|
|
ErrDuplicate = errors.New("duplicate key or address")
|
|
|
|
ErrMalformedEntry = errors.New("malformed entry")
|
|
|
|
ErrWatchingOnly = errors.New("keystore is watching-only")
|
|
|
|
ErrLocked = errors.New("keystore is locked")
|
|
|
|
ErrWrongPassphrase = errors.New("wrong passphrase")
|
2013-08-21 16:37:30 +02:00
|
|
|
)
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
var fileID = [8]byte{0xba, 'W', 'A', 'L', 'L', 'E', 'T', 0x00}
|
2013-09-03 06:10:32 +02:00
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
type entryHeader byte
|
|
|
|
|
|
|
|
const (
|
2021-03-24 14:43:24 +01:00
|
|
|
addrCommentHeader entryHeader = 1 << iota //nolint:varcheck,deadcode,unused
|
|
|
|
txCommentHeader // nolint:varcheck,deadcode,unused
|
|
|
|
deletedHeader // nolint:varcheck,deadcode,unused
|
2014-03-13 20:13:39 +01:00
|
|
|
scriptHeader
|
2013-08-21 16:37:30 +02:00
|
|
|
addrHeader entryHeader = 0
|
|
|
|
)
|
|
|
|
|
|
|
|
// We want to use binaryRead and binaryWrite instead of binary.Read
|
|
|
|
// and binary.Write because those from the binary package do not return
|
|
|
|
// the number of bytes actually written or read. We need to return
|
|
|
|
// this value to correctly support the io.ReaderFrom and io.WriterTo
|
|
|
|
// interfaces.
|
|
|
|
func binaryRead(r io.Reader, order binary.ByteOrder, data interface{}) (n int64, err error) {
|
|
|
|
var read int
|
|
|
|
buf := make([]byte, binary.Size(data))
|
2014-04-16 23:22:39 +02:00
|
|
|
if read, err = io.ReadFull(r, buf); err != nil {
|
2013-08-21 16:37:30 +02:00
|
|
|
return int64(read), err
|
|
|
|
}
|
|
|
|
return int64(read), binary.Read(bytes.NewBuffer(buf), order, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// See comment for binaryRead().
|
|
|
|
func binaryWrite(w io.Writer, order binary.ByteOrder, data interface{}) (n int64, err error) {
|
2014-06-05 05:23:32 +02:00
|
|
|
buf := bytes.Buffer{}
|
2013-08-21 16:37:30 +02:00
|
|
|
if err = binary.Write(&buf, order, data); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
written, err := w.Write(buf.Bytes())
|
|
|
|
return int64(written), err
|
|
|
|
}
|
|
|
|
|
2013-11-04 17:50:32 +01:00
|
|
|
// pubkeyFromPrivkey creates an encoded pubkey based on a
|
|
|
|
// 32-byte privkey. The returned pubkey is 33 bytes if compressed,
|
|
|
|
// or 65 bytes if uncompressed.
|
|
|
|
func pubkeyFromPrivkey(privkey []byte, compress bool) (pubkey []byte) {
|
2014-04-18 00:02:33 +02:00
|
|
|
_, pk := btcec.PrivKeyFromBytes(btcec.S256(), privkey)
|
2013-11-04 17:50:32 +01:00
|
|
|
|
|
|
|
if compress {
|
2014-04-18 00:02:33 +02:00
|
|
|
return pk.SerializeCompressed()
|
2013-11-04 17:50:32 +01:00
|
|
|
}
|
2014-04-18 00:02:33 +02:00
|
|
|
return pk.SerializeUncompressed()
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
func keyOneIter(passphrase, salt []byte, memReqts uint64) []byte {
|
|
|
|
saltedpass := append(passphrase, salt...)
|
|
|
|
lutbl := make([]byte, memReqts)
|
|
|
|
|
|
|
|
// Seed for lookup table
|
2014-01-06 18:24:29 +01:00
|
|
|
seed := sha512.Sum512(saltedpass)
|
|
|
|
copy(lutbl[:sha512.Size], seed[:])
|
2013-08-21 16:37:30 +02:00
|
|
|
|
|
|
|
for nByte := 0; nByte < (int(memReqts) - sha512.Size); nByte += sha512.Size {
|
2014-01-06 18:24:29 +01:00
|
|
|
hash := sha512.Sum512(lutbl[nByte : nByte+sha512.Size])
|
2013-08-21 16:37:30 +02:00
|
|
|
copy(lutbl[nByte+sha512.Size:nByte+2*sha512.Size], hash[:])
|
|
|
|
}
|
|
|
|
|
|
|
|
x := lutbl[cap(lutbl)-sha512.Size:]
|
|
|
|
|
|
|
|
seqCt := uint32(memReqts / sha512.Size)
|
|
|
|
nLookups := seqCt / 2
|
|
|
|
for i := uint32(0); i < nLookups; i++ {
|
|
|
|
// Armory ignores endianness here. We assume LE.
|
|
|
|
newIdx := binary.LittleEndian.Uint32(x[cap(x)-4:]) % seqCt
|
|
|
|
|
|
|
|
// Index of hash result at newIdx
|
|
|
|
vIdx := newIdx * sha512.Size
|
|
|
|
v := lutbl[vIdx : vIdx+sha512.Size]
|
|
|
|
|
|
|
|
// XOR hash x with hash v
|
|
|
|
for j := 0; j < sha512.Size; j++ {
|
|
|
|
x[j] ^= v[j]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save new hash to x
|
2014-01-06 18:24:29 +01:00
|
|
|
hash := sha512.Sum512(x)
|
2013-08-21 16:37:30 +02:00
|
|
|
copy(x, hash[:])
|
|
|
|
}
|
|
|
|
|
|
|
|
return x[:kdfOutputBytes]
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// kdf implements the key derivation function used by Armory
|
2013-08-21 16:37:30 +02:00
|
|
|
// based on the ROMix algorithm described in Colin Percival's paper
|
|
|
|
// "Stronger Key Derivation via Sequential Memory-Hard Functions"
|
|
|
|
// (http://www.tarsnap.com/scrypt/scrypt.pdf).
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func kdf(passphrase []byte, params *kdfParameters) []byte {
|
2013-08-21 16:37:30 +02:00
|
|
|
masterKey := passphrase
|
2013-09-03 06:10:32 +02:00
|
|
|
for i := uint32(0); i < params.nIter; i++ {
|
|
|
|
masterKey = keyOneIter(masterKey, params.salt[:], params.mem)
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
return masterKey
|
|
|
|
}
|
|
|
|
|
2013-11-04 17:50:32 +01:00
|
|
|
func pad(size int, b []byte) []byte {
|
|
|
|
// Prevent a possible panic if the input exceeds the expected size.
|
|
|
|
if len(b) > size {
|
|
|
|
size = len(b)
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
2013-11-04 17:50:32 +01:00
|
|
|
|
|
|
|
p := make([]byte, size)
|
|
|
|
copy(p[size-len(b):], b)
|
|
|
|
return p
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// chainedPrivKey deterministically generates a new private key using a
|
2013-09-03 06:10:32 +02:00
|
|
|
// previous address and chaincode. privkey and chaincode must be 32
|
2014-01-16 17:50:08 +01:00
|
|
|
// bytes long, and pubkey may either be 33 or 65 bytes.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func chainedPrivKey(privkey, pubkey, chaincode []byte) ([]byte, error) {
|
2013-09-03 06:10:32 +02:00
|
|
|
if len(privkey) != 32 {
|
2013-09-09 20:14:57 +02:00
|
|
|
return nil, fmt.Errorf("invalid privkey length %d (must be 32)",
|
2013-09-03 06:10:32 +02:00
|
|
|
len(privkey))
|
|
|
|
}
|
|
|
|
if len(chaincode) != 32 {
|
2013-09-09 20:14:57 +02:00
|
|
|
return nil, fmt.Errorf("invalid chaincode length %d (must be 32)",
|
2013-09-03 06:10:32 +02:00
|
|
|
len(chaincode))
|
|
|
|
}
|
2014-05-20 15:12:43 +02:00
|
|
|
switch n := len(pubkey); n {
|
|
|
|
case btcec.PubKeyBytesLenUncompressed, btcec.PubKeyBytesLenCompressed:
|
|
|
|
// Correct length
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("invalid pubkey length %d", n)
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
xorbytes := make([]byte, 32)
|
2016-08-08 21:49:09 +02:00
|
|
|
chainMod := chainhash.DoubleHashB(pubkey)
|
2013-09-09 20:14:57 +02:00
|
|
|
for i := range xorbytes {
|
2013-09-03 06:10:32 +02:00
|
|
|
xorbytes[i] = chainMod[i] ^ chaincode[i]
|
|
|
|
}
|
|
|
|
chainXor := new(big.Int).SetBytes(xorbytes)
|
|
|
|
privint := new(big.Int).SetBytes(privkey)
|
|
|
|
|
|
|
|
t := new(big.Int).Mul(chainXor, privint)
|
|
|
|
b := t.Mod(t, btcec.S256().N).Bytes()
|
2013-11-04 17:50:32 +01:00
|
|
|
return pad(32, b), nil
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// chainedPubKey deterministically generates a new public key using a
|
2014-01-16 17:50:08 +01:00
|
|
|
// previous public key and chaincode. pubkey must be 33 or 65 bytes, and
|
|
|
|
// chaincode must be 32 bytes long.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func chainedPubKey(pubkey, chaincode []byte) ([]byte, error) {
|
2014-05-20 15:12:43 +02:00
|
|
|
var compressed bool
|
|
|
|
switch n := len(pubkey); n {
|
|
|
|
case btcec.PubKeyBytesLenUncompressed:
|
|
|
|
compressed = false
|
|
|
|
case btcec.PubKeyBytesLenCompressed:
|
|
|
|
compressed = true
|
|
|
|
default:
|
|
|
|
// Incorrect serialized pubkey length
|
|
|
|
return nil, fmt.Errorf("invalid pubkey length %d", n)
|
2014-01-16 17:50:08 +01:00
|
|
|
}
|
|
|
|
if len(chaincode) != 32 {
|
|
|
|
return nil, fmt.Errorf("invalid chaincode length %d (must be 32)",
|
|
|
|
len(chaincode))
|
|
|
|
}
|
|
|
|
|
|
|
|
xorbytes := make([]byte, 32)
|
2016-08-08 21:49:09 +02:00
|
|
|
chainMod := chainhash.DoubleHashB(pubkey)
|
2014-01-16 17:50:08 +01:00
|
|
|
for i := range xorbytes {
|
|
|
|
xorbytes[i] = chainMod[i] ^ chaincode[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
oldPk, err := btcec.ParsePubKey(pubkey, btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
newX, newY := btcec.S256().ScalarMult(oldPk.X, oldPk.Y, xorbytes)
|
2014-04-09 02:18:52 +02:00
|
|
|
newPk := &btcec.PublicKey{
|
2014-01-16 17:50:08 +01:00
|
|
|
Curve: btcec.S256(),
|
|
|
|
X: newX,
|
|
|
|
Y: newY,
|
|
|
|
}
|
|
|
|
|
2014-05-20 15:12:43 +02:00
|
|
|
if compressed {
|
|
|
|
return newPk.SerializeCompressed(), nil
|
2014-01-16 17:50:08 +01:00
|
|
|
}
|
2014-05-20 15:12:43 +02:00
|
|
|
return newPk.SerializeUncompressed(), nil
|
2014-01-16 17:50:08 +01:00
|
|
|
}
|
|
|
|
|
2013-12-06 21:37:07 +01:00
|
|
|
type version struct {
|
|
|
|
major byte
|
|
|
|
minor byte
|
|
|
|
bugfix byte
|
|
|
|
autoincrement byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enforce that version satisifies the io.ReaderFrom and
|
|
|
|
// io.WriterTo interfaces.
|
|
|
|
var _ io.ReaderFrom = &version{}
|
|
|
|
var _ io.WriterTo = &version{}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// readerFromVersion is an io.ReaderFrom and io.WriterTo that
|
2014-07-08 20:17:24 +02:00
|
|
|
// can specify any particular key store file format for reading
|
|
|
|
// depending on the key store file version.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
type readerFromVersion interface {
|
|
|
|
readFromVersion(version, io.Reader) (int64, error)
|
2013-12-06 21:37:07 +01:00
|
|
|
io.WriterTo
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v version) String() string {
|
|
|
|
str := fmt.Sprintf("%d.%d", v.major, v.minor)
|
|
|
|
if v.bugfix != 0x00 || v.autoincrement != 0x00 {
|
|
|
|
str += fmt.Sprintf(".%d", v.bugfix)
|
|
|
|
}
|
|
|
|
if v.autoincrement != 0x00 {
|
|
|
|
str += fmt.Sprintf(".%d", v.autoincrement)
|
|
|
|
}
|
|
|
|
return str
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v version) Uint32() uint32 {
|
|
|
|
return uint32(v.major)<<6 | uint32(v.minor)<<4 | uint32(v.bugfix)<<2 | uint32(v.autoincrement)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *version) ReadFrom(r io.Reader) (int64, error) {
|
|
|
|
// Read 4 bytes for the version.
|
2014-04-16 23:22:39 +02:00
|
|
|
var versBytes [4]byte
|
|
|
|
n, err := io.ReadFull(r, versBytes[:])
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
|
|
|
return int64(n), err
|
|
|
|
}
|
|
|
|
v.major = versBytes[0]
|
|
|
|
v.minor = versBytes[1]
|
|
|
|
v.bugfix = versBytes[2]
|
|
|
|
v.autoincrement = versBytes[3]
|
|
|
|
return int64(n), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *version) WriteTo(w io.Writer) (int64, error) {
|
|
|
|
// Write 4 bytes for the version.
|
|
|
|
versBytes := []byte{
|
|
|
|
v.major,
|
|
|
|
v.minor,
|
|
|
|
v.bugfix,
|
|
|
|
v.autoincrement,
|
|
|
|
}
|
|
|
|
n, err := w.Write(versBytes)
|
|
|
|
return int64(n), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// LT returns whether v is an earlier version than v2.
|
|
|
|
func (v version) LT(v2 version) bool {
|
|
|
|
switch {
|
|
|
|
case v.major < v2.major:
|
|
|
|
return true
|
|
|
|
|
|
|
|
case v.minor < v2.minor:
|
|
|
|
return true
|
|
|
|
|
|
|
|
case v.bugfix < v2.bugfix:
|
|
|
|
return true
|
|
|
|
|
|
|
|
case v.autoincrement < v2.autoincrement:
|
|
|
|
return true
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// EQ returns whether v2 is an equal version to v.
|
|
|
|
func (v version) EQ(v2 version) bool {
|
|
|
|
switch {
|
|
|
|
case v.major != v2.major:
|
|
|
|
return false
|
|
|
|
|
|
|
|
case v.minor != v2.minor:
|
|
|
|
return false
|
|
|
|
|
|
|
|
case v.bugfix != v2.bugfix:
|
|
|
|
return false
|
|
|
|
|
|
|
|
case v.autoincrement != v2.autoincrement:
|
|
|
|
return false
|
|
|
|
|
|
|
|
default:
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GT returns whether v is a later version than v2.
|
|
|
|
func (v version) GT(v2 version) bool {
|
|
|
|
switch {
|
|
|
|
case v.major > v2.major:
|
|
|
|
return true
|
|
|
|
|
|
|
|
case v.minor > v2.minor:
|
|
|
|
return true
|
|
|
|
|
|
|
|
case v.bugfix > v2.bugfix:
|
|
|
|
return true
|
|
|
|
|
|
|
|
case v.autoincrement > v2.autoincrement:
|
|
|
|
return true
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Various versions.
|
|
|
|
var (
|
|
|
|
// VersArmory is the latest version used by Armory.
|
|
|
|
VersArmory = version{1, 35, 0, 0}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Vers20LastBlocks is the version where key store files now hold
|
2013-12-06 21:37:07 +01:00
|
|
|
// the 20 most recently seen block hashes.
|
|
|
|
Vers20LastBlocks = version{1, 36, 0, 0}
|
|
|
|
|
2014-02-04 16:37:28 +01:00
|
|
|
// VersUnsetNeedsPrivkeyFlag is the bugfix version where the
|
|
|
|
// createPrivKeyNextUnlock address flag is correctly unset
|
|
|
|
// after creating and encrypting its private key after unlock.
|
|
|
|
// Otherwise, re-creating private keys will occur too early
|
|
|
|
// in the address chain and fail due to encrypting an already
|
2014-07-08 20:17:24 +02:00
|
|
|
// encrypted address. Key store versions at or before this
|
2014-02-04 16:37:28 +01:00
|
|
|
// version include a special case to allow the duplicate
|
|
|
|
// encrypt.
|
|
|
|
VersUnsetNeedsPrivkeyFlag = version{1, 36, 1, 0}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// VersCurrent is the current key store file version.
|
2014-02-04 16:37:28 +01:00
|
|
|
VersCurrent = VersUnsetNeedsPrivkeyFlag
|
2013-12-06 21:37:07 +01:00
|
|
|
)
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
type varEntries struct {
|
2014-07-08 20:17:24 +02:00
|
|
|
store *Store
|
2014-04-09 02:18:52 +02:00
|
|
|
entries []io.WriterTo
|
|
|
|
}
|
2013-08-21 16:37:30 +02:00
|
|
|
|
|
|
|
func (v *varEntries) WriteTo(w io.Writer) (n int64, err error) {
|
2014-04-09 02:18:52 +02:00
|
|
|
ss := v.entries
|
2013-08-21 16:37:30 +02:00
|
|
|
|
|
|
|
var written int64
|
|
|
|
for _, s := range ss {
|
|
|
|
var err error
|
|
|
|
if written, err = s.WriteTo(w); err != nil {
|
|
|
|
return n + written, err
|
|
|
|
}
|
|
|
|
n += written
|
|
|
|
}
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *varEntries) ReadFrom(r io.Reader) (n int64, err error) {
|
|
|
|
var read int64
|
|
|
|
|
|
|
|
// Remove any previous entries.
|
2014-04-09 02:18:52 +02:00
|
|
|
v.entries = nil
|
|
|
|
wts := v.entries
|
2013-08-21 16:37:30 +02:00
|
|
|
|
|
|
|
// Keep reading entries until an EOF is reached.
|
|
|
|
for {
|
|
|
|
var header entryHeader
|
|
|
|
if read, err = binaryRead(r, binary.LittleEndian, &header); err != nil {
|
|
|
|
// EOF here is not an error.
|
|
|
|
if err == io.EOF {
|
|
|
|
return n + read, nil
|
|
|
|
}
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
|
2013-09-09 20:14:57 +02:00
|
|
|
var wt io.WriterTo
|
2013-08-21 16:37:30 +02:00
|
|
|
switch header {
|
|
|
|
case addrHeader:
|
|
|
|
var entry addrEntry
|
2014-07-08 20:17:24 +02:00
|
|
|
entry.addr.store = v.store
|
2013-08-21 16:37:30 +02:00
|
|
|
if read, err = entry.ReadFrom(r); err != nil {
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
wt = &entry
|
2014-03-13 20:13:39 +01:00
|
|
|
case scriptHeader:
|
|
|
|
var entry scriptEntry
|
2014-07-08 20:17:24 +02:00
|
|
|
entry.script.store = v.store
|
2014-03-13 20:13:39 +01:00
|
|
|
if read, err = entry.ReadFrom(r); err != nil {
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
wt = &entry
|
2013-08-21 16:37:30 +02:00
|
|
|
default:
|
2013-09-09 20:14:57 +02:00
|
|
|
return n, fmt.Errorf("unknown entry header: %d", uint8(header))
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
if wt != nil {
|
|
|
|
wts = append(wts, wt)
|
2014-04-09 02:18:52 +02:00
|
|
|
v.entries = wts
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Key stores use a custom network parameters type so it can be an io.ReaderFrom.
|
|
|
|
// Due to the way and order that key stores are currently serialized and how
|
|
|
|
// address reading requires the key store's network parameters, setting and
|
|
|
|
// erroring on unknown key store networks must happen on the read itself and not
|
2014-05-27 19:50:51 +02:00
|
|
|
// after the fact. This is admitidly a hack, but with a bip32 keystore on the
|
|
|
|
// horizon I'm not too motivated to clean this up.
|
2015-02-06 06:51:37 +01:00
|
|
|
type netParams chaincfg.Params
|
2014-05-27 19:50:51 +02:00
|
|
|
|
|
|
|
func (net *netParams) ReadFrom(r io.Reader) (int64, error) {
|
|
|
|
var buf [4]byte
|
|
|
|
uint32Bytes := buf[:4]
|
|
|
|
|
|
|
|
n, err := io.ReadFull(r, uint32Bytes)
|
|
|
|
n64 := int64(n)
|
|
|
|
if err != nil {
|
|
|
|
return n64, err
|
|
|
|
}
|
|
|
|
|
2015-02-05 22:41:38 +01:00
|
|
|
switch wire.BitcoinNet(binary.LittleEndian.Uint32(uint32Bytes)) {
|
|
|
|
case wire.MainNet:
|
2015-02-06 06:51:37 +01:00
|
|
|
*net = (netParams)(chaincfg.MainNetParams)
|
2015-02-05 22:41:38 +01:00
|
|
|
case wire.TestNet3:
|
2015-02-06 06:51:37 +01:00
|
|
|
*net = (netParams)(chaincfg.TestNet3Params)
|
2015-02-05 22:41:38 +01:00
|
|
|
case wire.SimNet:
|
2015-02-06 06:51:37 +01:00
|
|
|
*net = (netParams)(chaincfg.SimNetParams)
|
2014-05-27 19:50:51 +02:00
|
|
|
default:
|
|
|
|
return n64, errors.New("unknown network")
|
|
|
|
}
|
|
|
|
return n64, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (net *netParams) WriteTo(w io.Writer) (int64, error) {
|
|
|
|
var buf [4]byte
|
|
|
|
uint32Bytes := buf[:4]
|
|
|
|
|
|
|
|
binary.LittleEndian.PutUint32(uint32Bytes, uint32(net.Net))
|
|
|
|
n, err := w.Write(uint32Bytes)
|
|
|
|
n64 := int64(n)
|
|
|
|
return n64, err
|
|
|
|
}
|
|
|
|
|
2014-03-13 20:13:39 +01:00
|
|
|
// Stringified byte slices for use as map lookup keys.
|
2014-03-11 02:28:40 +01:00
|
|
|
type addressKey string
|
2013-11-04 17:50:32 +01:00
|
|
|
|
2014-03-11 02:28:40 +01:00
|
|
|
func getAddressKey(addr btcutil.Address) addressKey {
|
|
|
|
return addressKey(addr.ScriptAddress())
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Store represents an key store in memory. It implements the
|
|
|
|
// io.ReaderFrom and io.WriterTo interfaces to read from and
|
2013-12-06 21:37:07 +01:00
|
|
|
// write to any type of byte streams, including files.
|
2014-07-08 20:17:24 +02:00
|
|
|
type Store struct {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// TODO: Use atomic operations for dirty so the reader lock
|
|
|
|
// doesn't need to be grabbed.
|
|
|
|
dirty bool
|
|
|
|
path string
|
|
|
|
dir string
|
|
|
|
file string
|
|
|
|
|
|
|
|
mtx sync.RWMutex
|
2014-02-04 16:37:28 +01:00
|
|
|
vers version
|
2014-05-27 19:50:51 +02:00
|
|
|
net *netParams
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
flags walletFlags
|
|
|
|
createDate int64
|
|
|
|
name [32]byte
|
|
|
|
desc [256]byte
|
|
|
|
highestUsed int64
|
|
|
|
kdfParams kdfParameters
|
|
|
|
keyGenerator btcAddress
|
|
|
|
|
|
|
|
// These are non-standard and fit in the extra 1024 bytes between the
|
|
|
|
// root address and the appended entries.
|
2013-12-06 21:37:07 +01:00
|
|
|
recent recentBlocks
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
addrMap map[addressKey]walletAddress
|
2013-08-21 16:37:30 +02:00
|
|
|
|
2014-01-15 23:29:01 +01:00
|
|
|
// The rest of the fields in this struct are not serialized.
|
2014-01-24 18:31:08 +01:00
|
|
|
passphrase []byte
|
2014-01-17 15:35:52 +01:00
|
|
|
secret []byte
|
2014-03-11 02:28:40 +01:00
|
|
|
chainIdxMap map[int64]btcutil.Address
|
|
|
|
importedAddrs []walletAddress
|
2014-01-17 01:28:34 +01:00
|
|
|
lastChainIdx int64
|
|
|
|
missingKeysStart int64
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// New creates and initializes a new Store. name's and desc's byte length
|
|
|
|
// must not exceed 32 and 256 bytes, respectively. All address private keys
|
|
|
|
// are encrypted with passphrase. The key store is returned locked.
|
2015-02-06 06:51:37 +01:00
|
|
|
func New(dir string, desc string, passphrase []byte, net *chaincfg.Params,
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
createdAt *BlockStamp) (*Store, error) {
|
2014-01-15 23:29:01 +01:00
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
// Check sizes of inputs.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if len(desc) > 256 {
|
2013-09-03 06:10:32 +02:00
|
|
|
return nil, errors.New("desc exceeds 256 byte maximum size")
|
|
|
|
}
|
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
// Randomly-generate rootkey and chaincode.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
rootkey := make([]byte, 32)
|
2013-11-13 23:25:50 +01:00
|
|
|
if _, err := rand.Read(rootkey); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
chaincode := make([]byte, 32)
|
2013-11-13 23:25:50 +01:00
|
|
|
if _, err := rand.Read(chaincode); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2013-11-11 21:30:50 +01:00
|
|
|
|
|
|
|
// Compute AES key and encrypt root address.
|
2013-11-15 17:59:37 +01:00
|
|
|
kdfp, err := computeKdfParameters(defaultKdfComputeTime, defaultKdfMaxMem)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
aeskey := kdf(passphrase, kdfp)
|
2013-09-03 06:10:32 +02:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Create and fill key store.
|
|
|
|
s := &Store{
|
2014-10-14 00:57:57 +02:00
|
|
|
path: filepath.Join(dir, Filename),
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
dir: dir,
|
2014-10-14 00:57:57 +02:00
|
|
|
file: Filename,
|
2014-02-04 16:37:28 +01:00
|
|
|
vers: VersCurrent,
|
2014-05-27 19:50:51 +02:00
|
|
|
net: (*netParams)(net),
|
2013-09-03 06:10:32 +02:00
|
|
|
flags: walletFlags{
|
|
|
|
useEncryption: true,
|
|
|
|
watchingOnly: false,
|
|
|
|
},
|
2014-04-09 02:18:52 +02:00
|
|
|
createDate: time.Now().Unix(),
|
|
|
|
highestUsed: rootKeyChainIdx,
|
|
|
|
kdfParams: *kdfp,
|
2013-12-06 21:37:07 +01:00
|
|
|
recent: recentBlocks{
|
|
|
|
lastHeight: createdAt.Height,
|
2016-08-08 21:49:09 +02:00
|
|
|
hashes: []*chainhash.Hash{
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
createdAt.Hash,
|
2013-12-06 21:37:07 +01:00
|
|
|
},
|
|
|
|
},
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
addrMap: make(map[addressKey]walletAddress),
|
|
|
|
chainIdxMap: make(map[int64]btcutil.Address),
|
|
|
|
lastChainIdx: rootKeyChainIdx,
|
|
|
|
missingKeysStart: rootKeyChainIdx,
|
|
|
|
secret: aeskey,
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
copy(s.desc[:], []byte(desc))
|
2013-09-03 06:10:32 +02:00
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// Create new root address from key and chaincode.
|
2014-07-08 20:17:24 +02:00
|
|
|
root, err := newRootBtcAddress(s, rootkey, nil, chaincode,
|
2014-04-09 02:18:52 +02:00
|
|
|
createdAt)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify root address keypairs.
|
|
|
|
if err := root.verifyKeypairs(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := root.encrypt(aeskey); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
s.keyGenerator = *root
|
2014-04-09 02:18:52 +02:00
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
// Add root address to maps.
|
2014-07-08 20:17:24 +02:00
|
|
|
rootAddr := s.keyGenerator.Address()
|
|
|
|
s.addrMap[getAddressKey(rootAddr)] = &s.keyGenerator
|
|
|
|
s.chainIdxMap[rootKeyChainIdx] = rootAddr
|
2013-09-03 06:10:32 +02:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// key store must be returned locked.
|
|
|
|
if err := s.Lock(); err != nil {
|
2013-11-21 17:57:28 +01:00
|
|
|
return nil, err
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
return s, nil
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// ReadFrom reads data from a io.Reader and saves it to a key store,
|
2013-08-21 16:37:30 +02:00
|
|
|
// returning the number of bytes read and any errors encountered.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) ReadFrom(r io.Reader) (n int64, err error) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
var read int64
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
s.net = &netParams{}
|
|
|
|
s.addrMap = make(map[addressKey]walletAddress)
|
|
|
|
s.chainIdxMap = make(map[int64]btcutil.Address)
|
2013-09-03 06:10:32 +02:00
|
|
|
|
|
|
|
var id [8]byte
|
2014-07-08 20:17:24 +02:00
|
|
|
appendedEntries := varEntries{store: s}
|
|
|
|
s.keyGenerator.store = s
|
2013-08-21 16:37:30 +02:00
|
|
|
|
|
|
|
// Iterate through each entry needing to be read. If data
|
|
|
|
// implements io.ReaderFrom, use its ReadFrom func. Otherwise,
|
|
|
|
// data is a pointer to a fixed sized value.
|
|
|
|
datas := []interface{}{
|
2013-09-03 06:10:32 +02:00
|
|
|
&id,
|
2014-07-08 20:17:24 +02:00
|
|
|
&s.vers,
|
|
|
|
s.net,
|
|
|
|
&s.flags,
|
2014-02-03 21:11:17 +01:00
|
|
|
make([]byte, 6), // Bytes for Armory unique ID
|
2014-07-08 20:17:24 +02:00
|
|
|
&s.createDate,
|
|
|
|
&s.name,
|
|
|
|
&s.desc,
|
|
|
|
&s.highestUsed,
|
|
|
|
&s.kdfParams,
|
2013-09-03 06:10:32 +02:00
|
|
|
make([]byte, 256),
|
2014-07-08 20:17:24 +02:00
|
|
|
&s.keyGenerator,
|
|
|
|
newUnusedSpace(1024, &s.recent),
|
2013-09-03 06:10:32 +02:00
|
|
|
&appendedEntries,
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
for _, data := range datas {
|
|
|
|
var err error
|
2013-12-06 21:37:07 +01:00
|
|
|
switch d := data.(type) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
case readerFromVersion:
|
|
|
|
read, err = d.readFromVersion(s.vers, r)
|
2013-12-06 21:37:07 +01:00
|
|
|
|
|
|
|
case io.ReaderFrom:
|
|
|
|
read, err = d.ReadFrom(r)
|
|
|
|
|
|
|
|
default:
|
|
|
|
read, err = binaryRead(r, binary.LittleEndian, d)
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
n += read
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
if id != fileID {
|
2013-09-09 20:14:57 +02:00
|
|
|
return n, errors.New("unknown file ID")
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2013-11-20 02:18:11 +01:00
|
|
|
// Add root address to address map.
|
2014-07-08 20:17:24 +02:00
|
|
|
rootAddr := s.keyGenerator.Address()
|
|
|
|
s.addrMap[getAddressKey(rootAddr)] = &s.keyGenerator
|
|
|
|
s.chainIdxMap[rootKeyChainIdx] = rootAddr
|
2014-08-06 15:44:20 +02:00
|
|
|
s.lastChainIdx = rootKeyChainIdx
|
2013-08-21 16:37:30 +02:00
|
|
|
|
|
|
|
// Fill unserializied fields.
|
2014-04-09 02:18:52 +02:00
|
|
|
wts := appendedEntries.entries
|
2013-08-21 16:37:30 +02:00
|
|
|
for _, wt := range wts {
|
2013-11-20 02:18:11 +01:00
|
|
|
switch e := wt.(type) {
|
2013-08-21 16:37:30 +02:00
|
|
|
case *addrEntry:
|
2014-04-09 02:18:52 +02:00
|
|
|
addr := e.addr.Address()
|
2014-07-08 20:17:24 +02:00
|
|
|
s.addrMap[getAddressKey(addr)] = &e.addr
|
2014-04-09 02:18:52 +02:00
|
|
|
if e.addr.Imported() {
|
2014-07-08 20:17:24 +02:00
|
|
|
s.importedAddrs = append(s.importedAddrs, &e.addr)
|
2013-11-20 02:18:11 +01:00
|
|
|
} else {
|
2014-07-08 20:17:24 +02:00
|
|
|
s.chainIdxMap[e.addr.chainIndex] = addr
|
|
|
|
if s.lastChainIdx < e.addr.chainIndex {
|
|
|
|
s.lastChainIdx = e.addr.chainIndex
|
2013-11-20 02:18:11 +01:00
|
|
|
}
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
2013-11-20 02:18:11 +01:00
|
|
|
|
2014-03-06 01:36:03 +01:00
|
|
|
// If the private keys have not been created yet, mark the
|
2014-07-08 20:17:24 +02:00
|
|
|
// earliest so all can be created on next key store unlock.
|
2014-01-17 01:28:34 +01:00
|
|
|
if e.addr.flags.createPrivKeyNextUnlock {
|
2014-01-20 18:56:27 +01:00
|
|
|
switch {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
case s.missingKeysStart == rootKeyChainIdx:
|
2014-01-20 18:56:27 +01:00
|
|
|
fallthrough
|
2014-07-08 20:17:24 +02:00
|
|
|
case e.addr.chainIndex < s.missingKeysStart:
|
|
|
|
s.missingKeysStart = e.addr.chainIndex
|
2014-01-17 01:28:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-13 20:13:39 +01:00
|
|
|
case *scriptEntry:
|
2014-04-09 02:18:52 +02:00
|
|
|
addr := e.script.Address()
|
2014-07-08 20:17:24 +02:00
|
|
|
s.addrMap[getAddressKey(addr)] = &e.script
|
2014-03-13 20:13:39 +01:00
|
|
|
// script are always imported.
|
2014-07-08 20:17:24 +02:00
|
|
|
s.importedAddrs = append(s.importedAddrs, &e.script)
|
2014-03-13 20:13:39 +01:00
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
default:
|
2013-09-09 20:14:57 +02:00
|
|
|
return n, errors.New("unknown appended entry")
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// WriteTo serializes a key store and writes it to a io.Writer,
|
2013-09-03 06:10:32 +02:00
|
|
|
// returning the number of bytes written and any errors encountered.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) WriteTo(w io.Writer) (n int64, err error) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
|
|
|
return s.writeTo(w)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Store) writeTo(w io.Writer) (n int64, err error) {
|
2013-11-20 02:18:11 +01:00
|
|
|
var wts []io.WriterTo
|
2014-07-08 20:17:24 +02:00
|
|
|
var chainedAddrs = make([]io.WriterTo, len(s.chainIdxMap)-1)
|
2013-11-20 02:18:11 +01:00
|
|
|
var importedAddrs []io.WriterTo
|
2014-07-08 20:17:24 +02:00
|
|
|
for _, wAddr := range s.addrMap {
|
2014-03-11 02:28:40 +01:00
|
|
|
switch btcAddr := wAddr.(type) {
|
|
|
|
case *btcAddress:
|
|
|
|
e := &addrEntry{
|
|
|
|
addr: *btcAddr,
|
|
|
|
}
|
2014-04-09 02:18:52 +02:00
|
|
|
copy(e.pubKeyHash160[:], btcAddr.AddrHash())
|
|
|
|
if btcAddr.Imported() {
|
2014-03-11 02:28:40 +01:00
|
|
|
// No order for imported addresses.
|
|
|
|
importedAddrs = append(importedAddrs, e)
|
|
|
|
} else if btcAddr.chainIndex >= 0 {
|
|
|
|
// Chained addresses are sorted. This is
|
|
|
|
// kind of nice but probably isn't necessary.
|
|
|
|
chainedAddrs[btcAddr.chainIndex] = e
|
|
|
|
}
|
2014-03-13 20:13:39 +01:00
|
|
|
|
|
|
|
case *scriptAddress:
|
|
|
|
e := &scriptEntry{
|
|
|
|
script: *btcAddr,
|
|
|
|
}
|
2014-04-09 02:18:52 +02:00
|
|
|
copy(e.scriptHash160[:], btcAddr.AddrHash())
|
2014-03-13 20:13:39 +01:00
|
|
|
// scripts are always imported
|
|
|
|
importedAddrs = append(importedAddrs, e)
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
}
|
2021-03-24 14:43:24 +01:00
|
|
|
wts = append(chainedAddrs, importedAddrs...) // nolint:gocritic
|
2014-07-08 20:17:24 +02:00
|
|
|
appendedEntries := varEntries{store: s, entries: wts}
|
2013-09-03 06:10:32 +02:00
|
|
|
|
|
|
|
// Iterate through each entry needing to be written. If data
|
|
|
|
// implements io.WriterTo, use its WriteTo func. Otherwise,
|
|
|
|
// data is a pointer to a fixed size value.
|
|
|
|
datas := []interface{}{
|
|
|
|
&fileID,
|
2013-12-06 21:37:07 +01:00
|
|
|
&VersCurrent,
|
2014-07-08 20:17:24 +02:00
|
|
|
s.net,
|
|
|
|
&s.flags,
|
2014-02-04 16:37:28 +01:00
|
|
|
make([]byte, 6), // Bytes for Armory unique ID
|
2014-07-08 20:17:24 +02:00
|
|
|
&s.createDate,
|
|
|
|
&s.name,
|
|
|
|
&s.desc,
|
|
|
|
&s.highestUsed,
|
|
|
|
&s.kdfParams,
|
2013-09-03 06:10:32 +02:00
|
|
|
make([]byte, 256),
|
2014-07-08 20:17:24 +02:00
|
|
|
&s.keyGenerator,
|
|
|
|
newUnusedSpace(1024, &s.recent),
|
2013-09-03 06:10:32 +02:00
|
|
|
&appendedEntries,
|
|
|
|
}
|
|
|
|
var written int64
|
|
|
|
for _, data := range datas {
|
|
|
|
if s, ok := data.(io.WriterTo); ok {
|
2014-07-08 20:17:24 +02:00
|
|
|
written, err = s.WriteTo(w)
|
2013-09-03 06:10:32 +02:00
|
|
|
} else {
|
2014-07-08 20:17:24 +02:00
|
|
|
written, err = binaryWrite(w, binary.LittleEndian, data)
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
n += written
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// TODO: set this automatically.
|
|
|
|
func (s *Store) MarkDirty() {
|
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
|
|
|
s.dirty = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Store) WriteIfDirty() error {
|
|
|
|
s.mtx.RLock()
|
|
|
|
if !s.dirty {
|
|
|
|
s.mtx.RUnlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TempFile creates the file 0600, so no need to chmod it.
|
|
|
|
fi, err := ioutil.TempFile(s.dir, s.file)
|
|
|
|
if err != nil {
|
|
|
|
s.mtx.RUnlock()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fiPath := fi.Name()
|
|
|
|
|
|
|
|
_, err = s.writeTo(fi)
|
|
|
|
if err != nil {
|
|
|
|
s.mtx.RUnlock()
|
|
|
|
fi.Close()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = fi.Sync()
|
|
|
|
if err != nil {
|
|
|
|
s.mtx.RUnlock()
|
|
|
|
fi.Close()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fi.Close()
|
|
|
|
|
|
|
|
err = rename.Atomic(fiPath, s.path)
|
|
|
|
s.mtx.RUnlock()
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
s.mtx.Lock()
|
|
|
|
s.dirty = false
|
|
|
|
s.mtx.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenDir opens a new key store from the specified directory. If the file
|
|
|
|
// does not exist, the error from the os package will be returned, and can
|
|
|
|
// be checked with os.IsNotExist to differentiate missing file errors from
|
|
|
|
// others (including deserialization).
|
|
|
|
func OpenDir(dir string) (*Store, error) {
|
2014-10-14 00:57:57 +02:00
|
|
|
path := filepath.Join(dir, Filename)
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
fi, err := os.OpenFile(path, os.O_RDONLY, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer fi.Close()
|
|
|
|
store := new(Store)
|
|
|
|
_, err = store.ReadFrom(fi)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
store.path = path
|
|
|
|
store.dir = dir
|
2014-10-14 00:57:57 +02:00
|
|
|
store.file = Filename
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
return store, nil
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Unlock derives an AES key from passphrase and key store's KDF
|
|
|
|
// parameters and unlocks the root key of the key store. If
|
|
|
|
// the unlock was successful, the key store's secret key is saved,
|
2014-01-17 01:28:34 +01:00
|
|
|
// allowing the decryption of any encrypted private key. Any
|
2014-07-08 20:17:24 +02:00
|
|
|
// addresses created while the key store was locked without private
|
2014-01-17 01:28:34 +01:00
|
|
|
// keys are created at this time.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) Unlock(passphrase []byte) error {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if s.flags.watchingOnly {
|
|
|
|
return ErrWatchingOnly
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
// Derive key from KDF parameters and passphrase.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
key := kdf(passphrase, &s.kdfParams)
|
2013-08-21 16:37:30 +02:00
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
// Unlock root address with derived key.
|
2014-07-08 20:17:24 +02:00
|
|
|
if _, err := s.keyGenerator.unlock(key); err != nil {
|
2013-08-21 19:25:22 +02:00
|
|
|
return err
|
|
|
|
}
|
2013-11-11 21:30:50 +01:00
|
|
|
|
2014-01-24 18:31:08 +01:00
|
|
|
// If unlock was successful, save the passphrase and aes key.
|
2014-07-08 20:17:24 +02:00
|
|
|
s.passphrase = passphrase
|
|
|
|
s.secret = key
|
2014-01-17 01:28:34 +01:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
return s.createMissingPrivateKeys()
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
// Lock performs a best try effort to remove and zero all secret keys
|
2014-07-08 20:17:24 +02:00
|
|
|
// associated with the key store.
|
|
|
|
func (s *Store) Lock() (err error) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if s.flags.watchingOnly {
|
|
|
|
return ErrWatchingOnly
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Remove clear text passphrase from key store.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if s.isLocked() {
|
2014-07-08 20:17:24 +02:00
|
|
|
err = ErrLocked
|
2013-11-11 21:30:50 +01:00
|
|
|
} else {
|
2014-07-08 20:17:24 +02:00
|
|
|
zero(s.passphrase)
|
|
|
|
s.passphrase = nil
|
|
|
|
zero(s.secret)
|
|
|
|
s.secret = nil
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
// Remove clear text private keys from all address entries.
|
2014-07-08 20:17:24 +02:00
|
|
|
for _, addr := range s.addrMap {
|
2014-03-17 15:24:14 +01:00
|
|
|
if baddr, ok := addr.(*btcAddress); ok {
|
2014-03-14 01:26:03 +01:00
|
|
|
_ = baddr.lock()
|
|
|
|
}
|
2013-08-21 19:25:22 +02:00
|
|
|
}
|
2013-09-03 06:10:32 +02:00
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2014-01-27 15:30:42 +01:00
|
|
|
// ChangePassphrase creates a new AES key from a new passphrase and
|
|
|
|
// re-encrypts all encrypted private keys with the new key.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) ChangePassphrase(new []byte) error {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if s.flags.watchingOnly {
|
|
|
|
return ErrWatchingOnly
|
2014-01-27 15:30:42 +01:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if s.isLocked() {
|
2014-07-08 20:17:24 +02:00
|
|
|
return ErrLocked
|
2014-01-27 15:30:42 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
oldkey := s.secret
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
newkey := kdf(new, &s.kdfParams)
|
2014-01-27 15:30:42 +01:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
for _, wa := range s.addrMap {
|
2014-03-11 02:28:40 +01:00
|
|
|
// Only btcAddresses curently have private keys.
|
|
|
|
a, ok := wa.(*btcAddress)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2014-01-27 15:30:42 +01:00
|
|
|
if err := a.changeEncryptionKey(oldkey, newkey); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// zero old secrets.
|
2014-07-08 20:17:24 +02:00
|
|
|
zero(s.passphrase)
|
|
|
|
zero(s.secret)
|
2014-01-27 15:30:42 +01:00
|
|
|
|
|
|
|
// Save new secrets.
|
2014-07-08 20:17:24 +02:00
|
|
|
s.passphrase = new
|
|
|
|
s.secret = newkey
|
2014-01-27 15:30:42 +01:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
func zero(b []byte) {
|
|
|
|
for i := range b {
|
|
|
|
b[i] = 0
|
|
|
|
}
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// IsLocked returns whether a key store is unlocked (in which case the
|
2013-09-03 06:10:32 +02:00
|
|
|
// key is saved in memory), or locked.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) IsLocked() bool {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
|
|
|
return s.isLocked()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Store) isLocked() bool {
|
2014-07-08 20:17:24 +02:00
|
|
|
return len(s.secret) != 32
|
2013-08-21 20:46:20 +02:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// NextChainedAddress attempts to get the next chained address. If the key
|
|
|
|
// store is unlocked, the next pubkey and private key of the address chain are
|
|
|
|
// derived. If the key store is locke, only the next pubkey is derived, and
|
|
|
|
// the private key will be generated on next unlock.
|
|
|
|
func (s *Store) NextChainedAddress(bs *BlockStamp) (btcutil.Address, error) {
|
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
|
|
|
return s.nextChainedAddress(bs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Store) nextChainedAddress(bs *BlockStamp) (btcutil.Address, error) {
|
|
|
|
addr, err := s.nextChainedBtcAddress(bs)
|
2014-02-03 16:21:47 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2014-04-09 02:18:52 +02:00
|
|
|
return addr.Address(), nil
|
2014-02-03 16:21:47 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// ChangeAddress returns the next chained address from the key store, marking
|
|
|
|
// the address for a change transaction output.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (s *Store) ChangeAddress(bs *BlockStamp) (btcutil.Address, error) {
|
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
|
|
|
addr, err := s.nextChainedBtcAddress(bs)
|
2014-02-03 16:21:47 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
addr.flags.change = true
|
2014-01-15 23:29:01 +01:00
|
|
|
|
2014-02-03 16:21:47 +01:00
|
|
|
// Create and return payment address for address hash.
|
2014-04-09 02:18:52 +02:00
|
|
|
return addr.Address(), nil
|
2014-02-03 16:21:47 +01:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (s *Store) nextChainedBtcAddress(bs *BlockStamp) (*btcAddress, error) {
|
2013-11-11 21:30:50 +01:00
|
|
|
// Attempt to get address hash of next chained address.
|
2014-07-08 20:17:24 +02:00
|
|
|
nextAPKH, ok := s.chainIdxMap[s.highestUsed+1]
|
2013-11-20 02:18:11 +01:00
|
|
|
if !ok {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if s.isLocked() {
|
|
|
|
// Chain pubkeys.
|
|
|
|
if err := s.extendLocked(bs); err != nil {
|
2014-01-17 01:28:34 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// Chain private and pubkeys.
|
|
|
|
if err := s.extendUnlocked(bs); err != nil {
|
2014-01-17 01:28:34 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
2013-11-21 17:57:28 +01:00
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
// Should be added to the internal maps, try lookup again.
|
2014-07-08 20:17:24 +02:00
|
|
|
nextAPKH, ok = s.chainIdxMap[s.highestUsed+1]
|
2013-11-21 17:57:28 +01:00
|
|
|
if !ok {
|
2014-01-06 18:24:29 +01:00
|
|
|
return nil, errors.New("chain index map inproperly updated")
|
2013-11-21 17:57:28 +01:00
|
|
|
}
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
2013-11-11 21:30:50 +01:00
|
|
|
|
|
|
|
// Look up address.
|
2014-07-08 20:17:24 +02:00
|
|
|
addr, ok := s.addrMap[getAddressKey(nextAPKH)]
|
2013-11-21 17:57:28 +01:00
|
|
|
if !ok {
|
2014-01-06 18:24:29 +01:00
|
|
|
return nil, errors.New("cannot find generated address")
|
2013-09-09 20:14:57 +02:00
|
|
|
}
|
2013-11-11 21:30:50 +01:00
|
|
|
|
2014-03-11 02:28:40 +01:00
|
|
|
btcAddr, ok := addr.(*btcAddress)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("found non-pubkey chained address")
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
s.highestUsed++
|
2013-11-21 17:57:28 +01:00
|
|
|
|
2014-03-11 02:28:40 +01:00
|
|
|
return btcAddr, nil
|
2013-12-31 19:11:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// LastChainedAddress returns the most recently requested chained
|
|
|
|
// address from calling NextChainedAddress, or the root address if
|
|
|
|
// no chained addresses have been requested.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) LastChainedAddress() btcutil.Address {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
return s.chainIdxMap[s.highestUsed]
|
2013-09-09 20:14:57 +02:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// extendUnlocked grows address chain for an unlocked keystore.
|
|
|
|
func (s *Store) extendUnlocked(bs *BlockStamp) error {
|
2013-11-21 17:57:28 +01:00
|
|
|
// Get last chained address. New chained addresses will be
|
|
|
|
// chained off of this address's chaincode and private key.
|
2014-07-08 20:17:24 +02:00
|
|
|
a := s.chainIdxMap[s.lastChainIdx]
|
|
|
|
waddr, ok := s.addrMap[getAddressKey(a)]
|
2013-11-21 17:57:28 +01:00
|
|
|
if !ok {
|
|
|
|
return errors.New("expected last chained address not found")
|
|
|
|
}
|
2014-03-14 01:26:03 +01:00
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if s.isLocked() {
|
2014-07-08 20:17:24 +02:00
|
|
|
return ErrLocked
|
2014-01-17 16:29:44 +01:00
|
|
|
}
|
2014-03-11 02:28:40 +01:00
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
lastAddr, ok := waddr.(*btcAddress)
|
2014-03-11 02:28:40 +01:00
|
|
|
if !ok {
|
|
|
|
return errors.New("found non-pubkey chained address")
|
|
|
|
}
|
2014-03-14 01:26:03 +01:00
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
privkey, err := lastAddr.unlock(s.secret)
|
2014-03-14 01:26:03 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
cc := lastAddr.chaincode[:]
|
2013-11-21 17:57:28 +01:00
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
privkey, err = chainedPrivKey(privkey, lastAddr.pubKeyBytes(), cc)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2013-11-21 17:57:28 +01:00
|
|
|
}
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
newAddr, err := newBtcAddress(s, privkey, nil, bs, true)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := newAddr.verifyKeypairs(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err = newAddr.encrypt(s.secret); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a = newAddr.Address()
|
|
|
|
s.addrMap[getAddressKey(a)] = newAddr
|
|
|
|
newAddr.chainIndex = lastAddr.chainIndex + 1
|
|
|
|
s.chainIdxMap[newAddr.chainIndex] = a
|
|
|
|
s.lastChainIdx++
|
|
|
|
copy(newAddr.chaincode[:], cc)
|
2013-11-21 17:57:28 +01:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// extendLocked creates one new address without a private key (allowing for
|
|
|
|
// extending the address chain from a locked key store) chained from the
|
|
|
|
// last used chained address and adds the address to the key store's internal
|
|
|
|
// bookkeeping structures.
|
|
|
|
func (s *Store) extendLocked(bs *BlockStamp) error {
|
2014-07-08 20:17:24 +02:00
|
|
|
a := s.chainIdxMap[s.lastChainIdx]
|
|
|
|
waddr, ok := s.addrMap[getAddressKey(a)]
|
2014-01-17 01:28:34 +01:00
|
|
|
if !ok {
|
|
|
|
return errors.New("expected last chained address not found")
|
|
|
|
}
|
|
|
|
|
2014-03-11 02:28:40 +01:00
|
|
|
addr, ok := waddr.(*btcAddress)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("found non-pubkey chained address")
|
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
cc := addr.chaincode[:]
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
nextPubkey, err := chainedPubKey(addr.pubKeyBytes(), cc)
|
2014-01-17 01:28:34 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
newaddr, err := newBtcAddressWithoutPrivkey(s, nextPubkey, nil, bs)
|
2014-01-17 01:28:34 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-04-09 02:18:52 +02:00
|
|
|
a = newaddr.Address()
|
2014-07-08 20:17:24 +02:00
|
|
|
s.addrMap[getAddressKey(a)] = newaddr
|
2014-01-17 01:28:34 +01:00
|
|
|
newaddr.chainIndex = addr.chainIndex + 1
|
2014-07-08 20:17:24 +02:00
|
|
|
s.chainIdxMap[newaddr.chainIndex] = a
|
|
|
|
s.lastChainIdx++
|
2014-01-17 01:28:34 +01:00
|
|
|
copy(newaddr.chaincode[:], cc)
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if s.missingKeysStart == rootKeyChainIdx {
|
2014-07-08 20:17:24 +02:00
|
|
|
s.missingKeysStart = newaddr.chainIndex
|
2014-01-17 01:28:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) createMissingPrivateKeys() error {
|
|
|
|
idx := s.missingKeysStart
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if idx == rootKeyChainIdx {
|
2014-01-17 01:28:34 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup previous address.
|
2014-07-08 20:17:24 +02:00
|
|
|
apkh, ok := s.chainIdxMap[idx-1]
|
2014-01-17 01:28:34 +01:00
|
|
|
if !ok {
|
|
|
|
return errors.New("missing previous chained address")
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
prevWAddr := s.addrMap[getAddressKey(apkh)]
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if s.isLocked() {
|
2014-07-08 20:17:24 +02:00
|
|
|
return ErrLocked
|
2014-01-17 16:29:44 +01:00
|
|
|
}
|
2014-03-11 02:28:40 +01:00
|
|
|
|
|
|
|
prevAddr, ok := prevWAddr.(*btcAddress)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("found non-pubkey chained address")
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
prevPrivKey, err := prevAddr.unlock(s.secret)
|
2014-01-17 01:28:34 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := idx; ; i++ {
|
|
|
|
// Get the next private key for the ith address in the address chain.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
ithPrivKey, err := chainedPrivKey(prevPrivKey,
|
2014-04-09 02:18:52 +02:00
|
|
|
prevAddr.pubKeyBytes(), prevAddr.chaincode[:])
|
2014-01-17 01:28:34 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the address with the missing private key, set, and
|
|
|
|
// encrypt.
|
2014-07-08 20:17:24 +02:00
|
|
|
apkh, ok := s.chainIdxMap[i]
|
2014-01-17 01:28:34 +01:00
|
|
|
if !ok {
|
|
|
|
// Finished.
|
|
|
|
break
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
waddr := s.addrMap[getAddressKey(apkh)]
|
2014-03-11 02:28:40 +01:00
|
|
|
addr, ok := waddr.(*btcAddress)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("found non-pubkey chained address")
|
|
|
|
}
|
2014-01-17 01:28:34 +01:00
|
|
|
addr.privKeyCT = ithPrivKey
|
2014-07-08 20:17:24 +02:00
|
|
|
if err := addr.encrypt(s.secret); err != nil {
|
2014-02-04 16:37:28 +01:00
|
|
|
// Avoid bug: see comment for VersUnsetNeedsPrivkeyFlag.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if err != ErrAlreadyEncrypted || s.vers.LT(VersUnsetNeedsPrivkeyFlag) {
|
2014-02-04 16:37:28 +01:00
|
|
|
return err
|
|
|
|
}
|
2014-01-17 01:28:34 +01:00
|
|
|
}
|
2014-02-04 16:37:28 +01:00
|
|
|
addr.flags.createPrivKeyNextUnlock = false
|
2014-01-17 01:28:34 +01:00
|
|
|
|
|
|
|
// Set previous address and private key for next iteration.
|
|
|
|
prevAddr = addr
|
|
|
|
prevPrivKey = ithPrivKey
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.missingKeysStart = rootKeyChainIdx
|
2014-01-17 01:28:34 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Address returns an walletAddress structure for an address in a key store.
|
2014-04-09 02:18:52 +02:00
|
|
|
// This address may be typecast into other interfaces (like PubKeyAddress
|
|
|
|
// and ScriptAddress) if specific information e.g. keys is required.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) Address(a btcutil.Address) (WalletAddress, error) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
// Look up address by address hash.
|
2014-07-08 20:17:24 +02:00
|
|
|
btcaddr, ok := s.addrMap[getAddressKey(a)]
|
2013-11-04 17:50:32 +01:00
|
|
|
if !ok {
|
2014-01-06 18:24:29 +01:00
|
|
|
return nil, ErrAddressNotFound
|
2013-11-04 17:50:32 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
return btcaddr, nil
|
2013-11-04 17:50:32 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Net returns the bitcoin network parameters for this key store.
|
2015-02-06 06:51:37 +01:00
|
|
|
func (s *Store) Net() *chaincfg.Params {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
|
|
|
return s.netParams()
|
|
|
|
}
|
|
|
|
|
2015-02-06 06:51:37 +01:00
|
|
|
func (s *Store) netParams() *chaincfg.Params {
|
|
|
|
return (*chaincfg.Params)(s.net)
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// SetSyncStatus sets the sync status for a single key store address. This
|
|
|
|
// may error if the address is not found in the key store.
|
2014-03-27 16:32:56 +01:00
|
|
|
//
|
|
|
|
// When marking an address as unsynced, only the type Unsynced matters.
|
|
|
|
// The value is ignored.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) SetSyncStatus(a btcutil.Address, ss SyncStatus) error {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
wa, ok := s.addrMap[getAddressKey(a)]
|
2014-03-17 15:24:14 +01:00
|
|
|
if !ok {
|
|
|
|
return ErrAddressNotFound
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
wa.setSyncStatus(ss)
|
2014-03-17 15:24:14 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// SetSyncedWith marks already synced addresses in the key store to be in
|
2014-03-17 15:24:14 +01:00
|
|
|
// sync with the recently-seen block described by the blockstamp.
|
|
|
|
// Unsynced addresses are unaffected by this method and must be marked
|
|
|
|
// as in sync with MarkAddressSynced or MarkAllSynced to be considered
|
|
|
|
// in sync with bs.
|
2014-05-30 22:17:51 +02:00
|
|
|
//
|
2014-07-08 20:17:24 +02:00
|
|
|
// If bs is nil, the entire key store is marked unsynced.
|
|
|
|
func (s *Store) SetSyncedWith(bs *BlockStamp) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
2014-05-30 22:17:51 +02:00
|
|
|
if bs == nil {
|
2014-07-08 20:17:24 +02:00
|
|
|
s.recent.hashes = s.recent.hashes[:0]
|
|
|
|
s.recent.lastHeight = s.keyGenerator.firstBlock
|
|
|
|
s.keyGenerator.setSyncStatus(Unsynced(s.keyGenerator.firstBlock))
|
2014-05-30 22:17:51 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-12-06 21:37:07 +01:00
|
|
|
// Check if we're trying to rollback the last seen history.
|
|
|
|
// If so, and this bs is already saved, remove anything
|
|
|
|
// after and return. Otherwire, remove previous hashes.
|
2014-07-08 20:17:24 +02:00
|
|
|
if bs.Height < s.recent.lastHeight {
|
|
|
|
maybeIdx := len(s.recent.hashes) - 1 - int(s.recent.lastHeight-bs.Height)
|
|
|
|
if maybeIdx >= 0 && maybeIdx < len(s.recent.hashes) &&
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
*s.recent.hashes[maybeIdx] == *bs.Hash {
|
2013-12-06 21:37:07 +01:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
s.recent.lastHeight = bs.Height
|
2013-12-06 21:37:07 +01:00
|
|
|
// subslice out the removed hashes.
|
2014-07-08 20:17:24 +02:00
|
|
|
s.recent.hashes = s.recent.hashes[:maybeIdx]
|
2013-12-06 21:37:07 +01:00
|
|
|
return
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
s.recent.hashes = nil
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if bs.Height != s.recent.lastHeight+1 {
|
|
|
|
s.recent.hashes = nil
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
s.recent.lastHeight = bs.Height
|
2014-04-16 23:22:39 +02:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if len(s.recent.hashes) == 20 {
|
2013-12-06 21:37:07 +01:00
|
|
|
// Make room for the most recent hash.
|
2014-07-08 20:17:24 +02:00
|
|
|
copy(s.recent.hashes, s.recent.hashes[1:])
|
2013-12-06 21:37:07 +01:00
|
|
|
|
|
|
|
// Set new block in the last position.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.recent.hashes[19] = bs.Hash
|
2013-12-06 21:37:07 +01:00
|
|
|
} else {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.recent.hashes = append(s.recent.hashes, bs.Hash)
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// SyncHeight returns details about the block that a wallet is marked at least
|
|
|
|
// synced through. The height is the height that rescans should start at when
|
|
|
|
// syncing a wallet back to the best chain.
|
|
|
|
//
|
|
|
|
// NOTE: If the hash of the synced block is not known, hash will be nil, and
|
|
|
|
// must be obtained from elsewhere. This must be explicitly checked before
|
|
|
|
// dereferencing the pointer.
|
2016-08-08 21:49:09 +02:00
|
|
|
func (s *Store) SyncedTo() (hash *chainhash.Hash, height int32) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
switch h, ok := s.keyGenerator.SyncStatus().(PartialSync); {
|
|
|
|
case ok && int32(h) > s.recent.lastHeight:
|
2014-06-03 19:10:42 +02:00
|
|
|
height = int32(h)
|
|
|
|
default:
|
2014-07-08 20:17:24 +02:00
|
|
|
height = s.recent.lastHeight
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if n := len(s.recent.hashes); n != 0 {
|
|
|
|
hash = s.recent.hashes[n-1]
|
|
|
|
}
|
2014-06-03 19:10:42 +02:00
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
for _, a := range s.addrMap {
|
2014-03-27 16:32:56 +01:00
|
|
|
var syncHeight int32
|
2014-04-09 02:18:52 +02:00
|
|
|
switch e := a.SyncStatus().(type) {
|
2014-03-27 16:32:56 +01:00
|
|
|
case Unsynced:
|
|
|
|
syncHeight = int32(e)
|
|
|
|
case PartialSync:
|
|
|
|
syncHeight = int32(e)
|
|
|
|
case FullSync:
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if syncHeight < height {
|
|
|
|
height = syncHeight
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
hash = nil
|
2014-03-17 15:24:14 +01:00
|
|
|
|
|
|
|
// Can't go lower than 0.
|
|
|
|
if height == 0 {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
return
|
2014-03-17 15:24:14 +01:00
|
|
|
}
|
|
|
|
}
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
}
|
2021-03-24 14:43:24 +01:00
|
|
|
return // nolint:nakedret
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
}
|
|
|
|
|
2013-12-06 21:37:07 +01:00
|
|
|
// NewIterateRecentBlocks returns an iterator for recently-seen blocks.
|
|
|
|
// The iterator starts at the most recently-added block, and Prev should
|
|
|
|
// be used to access earlier blocks.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (s *Store) NewIterateRecentBlocks() *BlockIterator {
|
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
|
|
|
return s.recent.iter(s)
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
2014-05-22 00:50:47 +02:00
|
|
|
// ImportPrivateKey imports a WIF private key into the keystore. The imported
|
|
|
|
// address is created using either a compressed or uncompressed serialized
|
|
|
|
// public key, depending on the CompressPubKey bool of the WIF.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) ImportPrivateKey(wif *btcutil.WIF, bs *BlockStamp) (btcutil.Address, error) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if s.flags.watchingOnly {
|
|
|
|
return nil, ErrWatchingOnly
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
|
2014-01-15 20:07:08 +01:00
|
|
|
// First, must check that the key being imported will not result
|
|
|
|
// in a duplicate address.
|
2014-05-22 00:50:47 +02:00
|
|
|
pkh := btcutil.Hash160(wif.SerializePubKey())
|
2014-07-08 20:17:24 +02:00
|
|
|
if _, ok := s.addrMap[addressKey(pkh)]; ok {
|
2014-01-20 18:56:27 +01:00
|
|
|
return nil, ErrDuplicate
|
2014-01-15 20:07:08 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// The key store must be unlocked to encrypt the imported private key.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if s.isLocked() {
|
2014-07-08 20:17:24 +02:00
|
|
|
return nil, ErrLocked
|
2013-11-20 02:18:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create new address with this private key.
|
2014-05-22 00:50:47 +02:00
|
|
|
privKey := wif.PrivKey.Serialize()
|
2014-07-08 20:17:24 +02:00
|
|
|
btcaddr, err := newBtcAddress(s, privKey, nil, bs, wif.CompressPubKey)
|
2013-11-20 02:18:11 +01:00
|
|
|
if err != nil {
|
2014-01-20 18:56:27 +01:00
|
|
|
return nil, err
|
2013-11-20 02:18:11 +01:00
|
|
|
}
|
2014-01-06 18:24:29 +01:00
|
|
|
btcaddr.chainIndex = importedKeyChainIdx
|
2013-11-20 02:18:11 +01:00
|
|
|
|
2014-03-17 15:24:14 +01:00
|
|
|
// Mark as unsynced if import height is below currently-synced
|
|
|
|
// height.
|
2014-07-08 20:17:24 +02:00
|
|
|
if len(s.recent.hashes) != 0 && bs.Height < s.recent.lastHeight {
|
2014-03-17 15:24:14 +01:00
|
|
|
btcaddr.flags.unsynced = true
|
|
|
|
}
|
|
|
|
|
2013-11-20 02:18:11 +01:00
|
|
|
// Encrypt imported address with the derived AES key.
|
2014-07-08 20:17:24 +02:00
|
|
|
if err = btcaddr.encrypt(s.secret); err != nil {
|
2014-01-20 18:56:27 +01:00
|
|
|
return nil, err
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
2013-11-20 02:18:11 +01:00
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
addr := btcaddr.Address()
|
2014-07-08 20:17:24 +02:00
|
|
|
// Add address to key store's bookkeeping structures. Adding to
|
2013-11-20 02:18:11 +01:00
|
|
|
// the map will result in the imported address being serialized
|
|
|
|
// on the next WriteTo call.
|
2014-07-08 20:17:24 +02:00
|
|
|
s.addrMap[getAddressKey(addr)] = btcaddr
|
|
|
|
s.importedAddrs = append(s.importedAddrs, btcaddr)
|
2013-11-20 02:18:11 +01:00
|
|
|
|
2014-01-20 18:56:27 +01:00
|
|
|
// Create and return address.
|
2014-03-11 02:28:40 +01:00
|
|
|
return addr, nil
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2014-03-13 20:13:39 +01:00
|
|
|
// ImportScript creates a new scriptAddress with a user-provided script
|
2014-07-08 20:17:24 +02:00
|
|
|
// and adds it to the key store.
|
|
|
|
func (s *Store) ImportScript(script []byte, bs *BlockStamp) (btcutil.Address, error) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if s.flags.watchingOnly {
|
|
|
|
return nil, ErrWatchingOnly
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if _, ok := s.addrMap[addressKey(btcutil.Hash160(script))]; ok {
|
2014-03-13 20:13:39 +01:00
|
|
|
return nil, ErrDuplicate
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create new address with this private key.
|
2014-07-08 20:17:24 +02:00
|
|
|
scriptaddr, err := newScriptAddress(s, script, bs)
|
2014-03-13 20:13:39 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-03-17 15:24:14 +01:00
|
|
|
// Mark as unsynced if import height is below currently-synced
|
|
|
|
// height.
|
2014-07-08 20:17:24 +02:00
|
|
|
if len(s.recent.hashes) != 0 && bs.Height < s.recent.lastHeight {
|
2014-03-17 15:24:14 +01:00
|
|
|
scriptaddr.flags.unsynced = true
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Add address to key store's bookkeeping structures. Adding to
|
2014-03-13 20:13:39 +01:00
|
|
|
// the map will result in the imported address being serialized
|
|
|
|
// on the next WriteTo call.
|
2014-04-09 02:18:52 +02:00
|
|
|
addr := scriptaddr.Address()
|
2014-07-08 20:17:24 +02:00
|
|
|
s.addrMap[getAddressKey(addr)] = scriptaddr
|
|
|
|
s.importedAddrs = append(s.importedAddrs, scriptaddr)
|
2014-03-13 20:13:39 +01:00
|
|
|
|
|
|
|
// Create and return address.
|
|
|
|
return addr, nil
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// CreateDate returns the Unix time of the key store creation time. This
|
|
|
|
// is used to compare the key store creation time against block headers and
|
2013-12-09 23:03:51 +01:00
|
|
|
// set a better minimum block height of where to being rescans.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) CreateDate() int64 {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
return s.createDate
|
2013-12-09 23:03:51 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// ExportWatchingWallet creates and returns a new key store with the same
|
|
|
|
// addresses in w, but as a watching-only key store without any private keys.
|
|
|
|
// New addresses created by the watching key store will match the new addresses
|
|
|
|
// created the original key store (thanks to public key address chaining), but
|
2014-01-20 18:56:27 +01:00
|
|
|
// will be missing the associated private keys.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) ExportWatchingWallet() (*Store, error) {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Don't continue if key store is already watching-only.
|
|
|
|
if s.flags.watchingOnly {
|
|
|
|
return nil, ErrWatchingOnly
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Copy members of w into a new key store, but mark as watching-only and
|
2014-01-20 18:56:27 +01:00
|
|
|
// do not include any private keys.
|
2014-07-08 20:17:24 +02:00
|
|
|
ws := &Store{
|
|
|
|
vers: s.vers,
|
|
|
|
net: s.net,
|
2014-01-20 18:56:27 +01:00
|
|
|
flags: walletFlags{
|
|
|
|
useEncryption: false,
|
|
|
|
watchingOnly: true,
|
|
|
|
},
|
2014-07-08 20:17:24 +02:00
|
|
|
name: s.name,
|
|
|
|
desc: s.desc,
|
|
|
|
createDate: s.createDate,
|
|
|
|
highestUsed: s.highestUsed,
|
2014-01-20 18:56:27 +01:00
|
|
|
recent: recentBlocks{
|
2014-07-08 20:17:24 +02:00
|
|
|
lastHeight: s.recent.lastHeight,
|
2014-01-20 18:56:27 +01:00
|
|
|
},
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
addrMap: make(map[addressKey]walletAddress),
|
2014-01-20 18:56:27 +01:00
|
|
|
|
2014-03-14 01:26:03 +01:00
|
|
|
// todo oga make me a list
|
2014-03-11 02:28:40 +01:00
|
|
|
chainIdxMap: make(map[int64]btcutil.Address),
|
2014-07-08 20:17:24 +02:00
|
|
|
lastChainIdx: s.lastChainIdx,
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
kgwc := s.keyGenerator.watchingCopy(ws)
|
|
|
|
ws.keyGenerator = *(kgwc.(*btcAddress))
|
|
|
|
if len(s.recent.hashes) != 0 {
|
2016-08-08 21:49:09 +02:00
|
|
|
ws.recent.hashes = make([]*chainhash.Hash, 0, len(s.recent.hashes))
|
2014-07-08 20:17:24 +02:00
|
|
|
for _, hash := range s.recent.hashes {
|
2014-04-16 23:22:39 +02:00
|
|
|
hashCpy := *hash
|
2014-07-08 20:17:24 +02:00
|
|
|
ws.recent.hashes = append(ws.recent.hashes, &hashCpy)
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
for apkh, addr := range s.addrMap {
|
2014-04-09 02:18:52 +02:00
|
|
|
if !addr.Imported() {
|
2014-03-11 02:28:40 +01:00
|
|
|
// Must be a btcAddress if !imported.
|
|
|
|
btcAddr := addr.(*btcAddress)
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
ws.chainIdxMap[btcAddr.chainIndex] =
|
2014-04-09 02:18:52 +02:00
|
|
|
addr.Address()
|
2014-01-21 23:05:54 +01:00
|
|
|
}
|
2014-03-11 02:28:40 +01:00
|
|
|
apkhCopy := apkh
|
2014-07-08 20:17:24 +02:00
|
|
|
ws.addrMap[apkhCopy] = addr.watchingCopy(ws)
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
if len(s.importedAddrs) != 0 {
|
|
|
|
ws.importedAddrs = make([]walletAddress, 0,
|
|
|
|
len(s.importedAddrs))
|
|
|
|
for _, addr := range s.importedAddrs {
|
|
|
|
ws.importedAddrs = append(ws.importedAddrs, addr.watchingCopy(ws))
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
return ws, nil
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
|
2014-03-27 16:32:56 +01:00
|
|
|
// SyncStatus is the interface type for all sync variants.
|
|
|
|
type SyncStatus interface {
|
|
|
|
ImplementsSyncStatus()
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
type (
|
|
|
|
// Unsynced is a type representing an unsynced address. When this is
|
|
|
|
// returned by a key store method, the value is the recorded first seen
|
|
|
|
// block height.
|
|
|
|
Unsynced int32
|
|
|
|
|
|
|
|
// PartialSync is a type representing a partially synced address (for
|
|
|
|
// example, due to the result of a partially-completed rescan).
|
|
|
|
PartialSync int32
|
|
|
|
|
|
|
|
// FullSync is a type representing an address that is in sync with the
|
|
|
|
// recently seen blocks.
|
|
|
|
FullSync struct{}
|
|
|
|
)
|
2014-03-27 16:32:56 +01:00
|
|
|
|
|
|
|
// ImplementsSyncStatus is implemented to make Unsynced a SyncStatus.
|
|
|
|
func (u Unsynced) ImplementsSyncStatus() {}
|
|
|
|
|
|
|
|
// ImplementsSyncStatus is implemented to make PartialSync a SyncStatus.
|
|
|
|
func (p PartialSync) ImplementsSyncStatus() {}
|
|
|
|
|
|
|
|
// ImplementsSyncStatus is implemented to make FullSync a SyncStatus.
|
|
|
|
func (f FullSync) ImplementsSyncStatus() {}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// WalletAddress is an interface that provides acces to information regarding an
|
|
|
|
// address managed by a key store. Concrete implementations of this type may
|
2014-03-06 01:34:44 +01:00
|
|
|
// provide further fields to provide information specific to that type of
|
|
|
|
// address.
|
2014-04-09 02:18:52 +02:00
|
|
|
type WalletAddress interface {
|
2014-03-06 01:34:44 +01:00
|
|
|
// Address returns a btcutil.Address for the backing address.
|
|
|
|
Address() btcutil.Address
|
2014-04-09 02:18:52 +02:00
|
|
|
// AddrHash returns the key or script hash related to the address
|
|
|
|
AddrHash() string
|
2014-03-06 01:34:44 +01:00
|
|
|
// FirstBlock returns the first block an address could be in.
|
|
|
|
FirstBlock() int32
|
|
|
|
// Compressed returns true if the backing address was imported instead
|
|
|
|
// of being part of an address chain.
|
|
|
|
Imported() bool
|
|
|
|
// Compressed returns true if the backing address was created for a
|
|
|
|
// change output of a transaction.
|
|
|
|
Change() bool
|
|
|
|
// Compressed returns true if the backing address is compressed.
|
|
|
|
Compressed() bool
|
2014-03-27 16:32:56 +01:00
|
|
|
// SyncStatus returns the current synced state of an address.
|
|
|
|
SyncStatus() SyncStatus
|
2014-03-06 01:34:44 +01:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// SortedActiveAddresses returns all key store addresses that have been
|
2013-11-11 21:30:50 +01:00
|
|
|
// requested to be generated. These do not include unused addresses in
|
|
|
|
// the key pool. Use this when ordered addresses are needed. Otherwise,
|
2013-12-02 20:56:06 +01:00
|
|
|
// ActiveAddresses is preferred.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) SortedActiveAddresses() []WalletAddress {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
addrs := make([]WalletAddress, 0,
|
2014-07-08 20:17:24 +02:00
|
|
|
s.highestUsed+int64(len(s.importedAddrs))+1)
|
|
|
|
for i := int64(rootKeyChainIdx); i <= s.highestUsed; i++ {
|
|
|
|
a := s.chainIdxMap[i]
|
|
|
|
info, ok := s.addrMap[getAddressKey(a)]
|
2014-04-09 02:18:52 +02:00
|
|
|
if ok {
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
addrs = append(addrs, info)
|
2013-09-09 20:14:57 +02:00
|
|
|
}
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
for _, addr := range s.importedAddrs {
|
2014-04-09 02:18:52 +02:00
|
|
|
addrs = append(addrs, addr)
|
2013-11-20 02:18:11 +01:00
|
|
|
}
|
2013-08-21 16:37:30 +02:00
|
|
|
return addrs
|
|
|
|
}
|
|
|
|
|
2013-12-02 20:56:06 +01:00
|
|
|
// ActiveAddresses returns a map between active payment addresses
|
2013-11-11 21:30:50 +01:00
|
|
|
// and their full info. These do not include unused addresses in the
|
2013-12-02 20:56:06 +01:00
|
|
|
// key pool. If addresses must be sorted, use SortedActiveAddresses.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (s *Store) ActiveAddresses() map[btcutil.Address]WalletAddress {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
s.mtx.RLock()
|
|
|
|
defer s.mtx.RUnlock()
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
addrs := make(map[btcutil.Address]WalletAddress)
|
2014-07-08 20:17:24 +02:00
|
|
|
for i := int64(rootKeyChainIdx); i <= s.highestUsed; i++ {
|
|
|
|
a := s.chainIdxMap[i]
|
|
|
|
addr := s.addrMap[getAddressKey(a)]
|
2014-04-09 02:18:52 +02:00
|
|
|
addrs[addr.Address()] = addr
|
2013-11-06 17:23:30 +01:00
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
for _, addr := range s.importedAddrs {
|
2014-04-09 02:18:52 +02:00
|
|
|
addrs[addr.Address()] = addr
|
2013-11-20 02:18:11 +01:00
|
|
|
}
|
2013-11-06 17:23:30 +01:00
|
|
|
return addrs
|
|
|
|
}
|
|
|
|
|
2014-01-21 17:19:08 +01:00
|
|
|
// ExtendActiveAddresses gets or creates the next n addresses from the
|
|
|
|
// address chain and marks each as active. This is used to recover
|
2014-07-08 20:17:24 +02:00
|
|
|
// deterministic (not imported) addresses from a key store backup, or to
|
|
|
|
// keep the active addresses in sync between an encrypted key store with
|
|
|
|
// private keys and an exported watching key store without.
|
2014-01-21 17:19:08 +01:00
|
|
|
//
|
|
|
|
// A slice is returned with the btcutil.Address of each new address.
|
|
|
|
// The blockchain must be rescanned for these addresses.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (s *Store) ExtendActiveAddresses(n int) ([]btcutil.Address, error) {
|
|
|
|
s.mtx.Lock()
|
|
|
|
defer s.mtx.Unlock()
|
2014-01-21 17:19:08 +01:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
last := s.addrMap[getAddressKey(s.chainIdxMap[s.highestUsed])]
|
2014-04-09 02:18:52 +02:00
|
|
|
bs := &BlockStamp{Height: last.FirstBlock()}
|
2014-01-21 17:19:08 +01:00
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
addrs := make([]btcutil.Address, n)
|
2014-01-21 17:19:08 +01:00
|
|
|
for i := 0; i < n; i++ {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
addr, err := s.nextChainedAddress(bs)
|
2014-01-21 17:19:08 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
addrs[i] = addr
|
2014-01-21 17:19:08 +01:00
|
|
|
}
|
|
|
|
return addrs, nil
|
|
|
|
}
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
type walletFlags struct {
|
|
|
|
useEncryption bool
|
|
|
|
watchingOnly bool
|
|
|
|
}
|
|
|
|
|
2014-01-20 18:56:27 +01:00
|
|
|
func (wf *walletFlags) ReadFrom(r io.Reader) (int64, error) {
|
|
|
|
var b [8]byte
|
2014-04-16 23:22:39 +02:00
|
|
|
n, err := io.ReadFull(r, b[:])
|
2014-01-20 18:56:27 +01:00
|
|
|
if err != nil {
|
|
|
|
return int64(n), err
|
|
|
|
}
|
|
|
|
|
|
|
|
wf.useEncryption = b[0]&(1<<0) != 0
|
|
|
|
wf.watchingOnly = b[0]&(1<<1) != 0
|
|
|
|
|
|
|
|
return int64(n), nil
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2014-01-20 18:56:27 +01:00
|
|
|
func (wf *walletFlags) WriteTo(w io.Writer) (int64, error) {
|
|
|
|
var b [8]byte
|
2013-09-03 06:10:32 +02:00
|
|
|
if wf.useEncryption {
|
2014-01-20 18:56:27 +01:00
|
|
|
b[0] |= 1 << 0
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
if wf.watchingOnly {
|
2014-01-20 18:56:27 +01:00
|
|
|
b[0] |= 1 << 1
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
2014-01-20 18:56:27 +01:00
|
|
|
n, err := w.Write(b[:])
|
|
|
|
return int64(n), err
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
2013-08-21 16:37:30 +02:00
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
type addrFlags struct {
|
2013-11-04 17:50:32 +01:00
|
|
|
hasPrivKey bool
|
|
|
|
hasPubKey bool
|
|
|
|
encrypted bool
|
2014-01-20 18:56:27 +01:00
|
|
|
createPrivKeyNextUnlock bool
|
2013-11-04 17:50:32 +01:00
|
|
|
compressed bool
|
2014-02-03 16:21:47 +01:00
|
|
|
change bool
|
2014-03-17 15:24:14 +01:00
|
|
|
unsynced bool
|
2014-03-27 16:32:56 +01:00
|
|
|
partialSync bool
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
func (af *addrFlags) ReadFrom(r io.Reader) (int64, error) {
|
2013-09-03 06:10:32 +02:00
|
|
|
var b [8]byte
|
2014-04-16 23:22:39 +02:00
|
|
|
n, err := io.ReadFull(r, b[:])
|
2013-09-03 06:10:32 +02:00
|
|
|
if err != nil {
|
2014-01-17 01:28:34 +01:00
|
|
|
return int64(n), err
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
af.hasPrivKey = b[0]&(1<<0) != 0
|
|
|
|
af.hasPubKey = b[0]&(1<<1) != 0
|
|
|
|
af.encrypted = b[0]&(1<<2) != 0
|
|
|
|
af.createPrivKeyNextUnlock = b[0]&(1<<3) != 0
|
|
|
|
af.compressed = b[0]&(1<<4) != 0
|
2014-02-03 16:21:47 +01:00
|
|
|
af.change = b[0]&(1<<5) != 0
|
2014-03-17 15:24:14 +01:00
|
|
|
af.unsynced = b[0]&(1<<6) != 0
|
2014-03-27 16:32:56 +01:00
|
|
|
af.partialSync = b[0]&(1<<7) != 0
|
2014-01-17 01:28:34 +01:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Currently (at least until watching-only key stores are implemented)
|
2014-01-17 01:28:34 +01:00
|
|
|
// btcwallet shall refuse to open any unencrypted addresses. This
|
|
|
|
// check only makes sense if there is a private key to encrypt, which
|
|
|
|
// there may not be if the keypool was extended from just the last
|
|
|
|
// public key and no private keys were written.
|
|
|
|
if af.hasPrivKey && !af.encrypted {
|
|
|
|
return int64(n), errors.New("private key is unencrypted")
|
2013-11-04 17:50:32 +01:00
|
|
|
}
|
2013-09-03 06:10:32 +02:00
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
return int64(n), nil
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
func (af *addrFlags) WriteTo(w io.Writer) (int64, error) {
|
2013-09-03 06:10:32 +02:00
|
|
|
var b [8]byte
|
|
|
|
if af.hasPrivKey {
|
|
|
|
b[0] |= 1 << 0
|
|
|
|
}
|
|
|
|
if af.hasPubKey {
|
|
|
|
b[0] |= 1 << 1
|
|
|
|
}
|
2014-01-17 01:28:34 +01:00
|
|
|
if af.hasPrivKey && !af.encrypted {
|
2013-09-03 06:10:32 +02:00
|
|
|
// We only support encrypted privkeys.
|
2014-01-17 01:28:34 +01:00
|
|
|
return 0, errors.New("address must be encrypted")
|
|
|
|
}
|
|
|
|
if af.encrypted {
|
|
|
|
b[0] |= 1 << 2
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
2013-11-04 17:50:32 +01:00
|
|
|
if af.createPrivKeyNextUnlock {
|
|
|
|
b[0] |= 1 << 3
|
|
|
|
}
|
|
|
|
if af.compressed {
|
|
|
|
b[0] |= 1 << 4
|
|
|
|
}
|
2014-02-03 16:21:47 +01:00
|
|
|
if af.change {
|
|
|
|
b[0] |= 1 << 5
|
|
|
|
}
|
2014-03-17 15:24:14 +01:00
|
|
|
if af.unsynced {
|
|
|
|
b[0] |= 1 << 6
|
|
|
|
}
|
2014-03-27 16:32:56 +01:00
|
|
|
if af.partialSync {
|
|
|
|
b[0] |= 1 << 7
|
|
|
|
}
|
2013-09-03 06:10:32 +02:00
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
n, err := w.Write(b[:])
|
|
|
|
return int64(n), err
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2013-12-06 21:37:07 +01:00
|
|
|
// recentBlocks holds at most the last 20 seen block hashes as well as
|
|
|
|
// the block height of the most recently seen block.
|
|
|
|
type recentBlocks struct {
|
2016-08-08 21:49:09 +02:00
|
|
|
hashes []*chainhash.Hash
|
2013-12-06 21:37:07 +01:00
|
|
|
lastHeight int32
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (rb *recentBlocks) readFromVersion(v version, r io.Reader) (int64, error) {
|
2013-12-06 21:37:07 +01:00
|
|
|
if !v.LT(Vers20LastBlocks) {
|
|
|
|
// Use current version.
|
|
|
|
return rb.ReadFrom(r)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Old file versions only saved the most recently seen
|
|
|
|
// block height and hash, not the last 20.
|
|
|
|
|
|
|
|
var read int64
|
|
|
|
|
|
|
|
// Read height.
|
2014-04-16 23:22:39 +02:00
|
|
|
var heightBytes [4]byte // 4 bytes for a int32
|
|
|
|
n, err := io.ReadFull(r, heightBytes[:])
|
|
|
|
read += int64(n)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
2014-04-16 23:22:39 +02:00
|
|
|
return read, err
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
2014-04-16 23:22:39 +02:00
|
|
|
rb.lastHeight = int32(binary.LittleEndian.Uint32(heightBytes[:]))
|
2013-12-06 21:37:07 +01:00
|
|
|
|
|
|
|
// If height is -1, the last synced block is unknown, so don't try
|
|
|
|
// to read a block hash.
|
|
|
|
if rb.lastHeight == -1 {
|
|
|
|
rb.hashes = nil
|
|
|
|
return read, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read block hash.
|
2016-08-08 21:49:09 +02:00
|
|
|
var syncedBlockHash chainhash.Hash
|
2014-04-16 23:22:39 +02:00
|
|
|
n, err = io.ReadFull(r, syncedBlockHash[:])
|
|
|
|
read += int64(n)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
2014-04-16 23:22:39 +02:00
|
|
|
return read, err
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
2016-08-08 21:49:09 +02:00
|
|
|
rb.hashes = []*chainhash.Hash{
|
2013-12-06 21:37:07 +01:00
|
|
|
&syncedBlockHash,
|
|
|
|
}
|
|
|
|
|
|
|
|
return read, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rb *recentBlocks) ReadFrom(r io.Reader) (int64, error) {
|
|
|
|
var read int64
|
|
|
|
|
|
|
|
// Read number of saved blocks. This should not exceed 20.
|
2014-04-16 23:22:39 +02:00
|
|
|
var nBlockBytes [4]byte // 4 bytes for a uint32
|
|
|
|
n, err := io.ReadFull(r, nBlockBytes[:])
|
|
|
|
read += int64(n)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
2014-04-16 23:22:39 +02:00
|
|
|
return read, err
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
2014-04-16 23:22:39 +02:00
|
|
|
nBlocks := binary.LittleEndian.Uint32(nBlockBytes[:])
|
2013-12-06 21:37:07 +01:00
|
|
|
if nBlocks > 20 {
|
|
|
|
return read, errors.New("number of last seen blocks exceeds maximum of 20")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read most recently seen block height.
|
2014-04-16 23:22:39 +02:00
|
|
|
var heightBytes [4]byte // 4 bytes for a int32
|
|
|
|
n, err = io.ReadFull(r, heightBytes[:])
|
|
|
|
read += int64(n)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
2014-04-16 23:22:39 +02:00
|
|
|
return read, err
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
2014-04-16 23:22:39 +02:00
|
|
|
height := int32(binary.LittleEndian.Uint32(heightBytes[:]))
|
2013-12-06 21:37:07 +01:00
|
|
|
|
|
|
|
// height should not be -1 (or any other negative number)
|
|
|
|
// since at this point we should be reading in at least one
|
|
|
|
// known block.
|
|
|
|
if height < 0 {
|
|
|
|
return read, errors.New("expected a block but specified height is negative")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set last seen height.
|
|
|
|
rb.lastHeight = height
|
|
|
|
|
|
|
|
// Read nBlocks block hashes. Hashes are expected to be in
|
|
|
|
// order of oldest to newest, but there's no way to check
|
|
|
|
// that here.
|
2016-08-08 21:49:09 +02:00
|
|
|
rb.hashes = make([]*chainhash.Hash, 0, nBlocks)
|
2013-12-06 21:37:07 +01:00
|
|
|
for i := uint32(0); i < nBlocks; i++ {
|
2016-08-08 21:49:09 +02:00
|
|
|
var blockHash chainhash.Hash
|
|
|
|
n, err := io.ReadFull(r, blockHash[:])
|
2014-04-16 23:22:39 +02:00
|
|
|
read += int64(n)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
2014-04-16 23:22:39 +02:00
|
|
|
return read, err
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
2016-08-08 21:49:09 +02:00
|
|
|
rb.hashes = append(rb.hashes, &blockHash)
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return read, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rb *recentBlocks) WriteTo(w io.Writer) (int64, error) {
|
|
|
|
var written int64
|
|
|
|
|
|
|
|
// Write number of saved blocks. This should not exceed 20.
|
|
|
|
nBlocks := uint32(len(rb.hashes))
|
|
|
|
if nBlocks > 20 {
|
|
|
|
return written, errors.New("number of last seen blocks exceeds maximum of 20")
|
|
|
|
}
|
|
|
|
if nBlocks != 0 && rb.lastHeight < 0 {
|
|
|
|
return written, errors.New("number of block hashes is positive, but height is negative")
|
|
|
|
}
|
2014-04-16 23:22:39 +02:00
|
|
|
var nBlockBytes [4]byte // 4 bytes for a uint32
|
|
|
|
binary.LittleEndian.PutUint32(nBlockBytes[:], nBlocks)
|
|
|
|
n, err := w.Write(nBlockBytes[:])
|
|
|
|
written += int64(n)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
2014-04-16 23:22:39 +02:00
|
|
|
return written, err
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write most recently seen block height.
|
2014-04-16 23:22:39 +02:00
|
|
|
var heightBytes [4]byte // 4 bytes for a int32
|
|
|
|
binary.LittleEndian.PutUint32(heightBytes[:], uint32(rb.lastHeight))
|
|
|
|
n, err = w.Write(heightBytes[:])
|
|
|
|
written += int64(n)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
2014-04-16 23:22:39 +02:00
|
|
|
return written, err
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write block hashes.
|
|
|
|
for _, hash := range rb.hashes {
|
|
|
|
n, err := w.Write(hash[:])
|
2014-04-16 23:22:39 +02:00
|
|
|
written += int64(n)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
2014-04-16 23:22:39 +02:00
|
|
|
return written, err
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return written, nil
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
// BlockIterator allows for the forwards and backwards iteration of recently
|
|
|
|
// seen blocks.
|
|
|
|
type BlockIterator struct {
|
|
|
|
storeMtx *sync.RWMutex
|
|
|
|
height int32
|
|
|
|
index int
|
|
|
|
rb *recentBlocks
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (rb *recentBlocks) iter(s *Store) *BlockIterator {
|
2014-05-30 22:17:51 +02:00
|
|
|
if rb.lastHeight == -1 || len(rb.hashes) == 0 {
|
2013-12-06 21:37:07 +01:00
|
|
|
return nil
|
|
|
|
}
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
return &BlockIterator{
|
|
|
|
storeMtx: &s.mtx,
|
|
|
|
height: rb.lastHeight,
|
|
|
|
index: len(rb.hashes) - 1,
|
|
|
|
rb: rb,
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (it *BlockIterator) Next() bool {
|
|
|
|
it.storeMtx.RLock()
|
|
|
|
defer it.storeMtx.RUnlock()
|
|
|
|
|
2013-12-06 21:37:07 +01:00
|
|
|
if it.index+1 >= len(it.rb.hashes) {
|
|
|
|
return false
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
it.index++
|
2013-12-06 21:37:07 +01:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (it *BlockIterator) Prev() bool {
|
|
|
|
it.storeMtx.RLock()
|
|
|
|
defer it.storeMtx.RUnlock()
|
|
|
|
|
2013-12-06 21:37:07 +01:00
|
|
|
if it.index-1 < 0 {
|
|
|
|
return false
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
it.index--
|
2013-12-06 21:37:07 +01:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (it *BlockIterator) BlockStamp() BlockStamp {
|
|
|
|
it.storeMtx.RLock()
|
|
|
|
defer it.storeMtx.RUnlock()
|
|
|
|
|
|
|
|
return BlockStamp{
|
2013-12-06 21:37:07 +01:00
|
|
|
Height: it.rb.lastHeight - int32(len(it.rb.hashes)-1-it.index),
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
Hash: it.rb.hashes[it.index],
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// unusedSpace is a wrapper type to read or write one or more types
|
2014-07-08 20:17:24 +02:00
|
|
|
// that btcwallet fits into an unused space left by Armory's key store file
|
2013-12-06 21:37:07 +01:00
|
|
|
// format.
|
|
|
|
type unusedSpace struct {
|
|
|
|
nBytes int // number of unused bytes that armory left.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
rfvs []readerFromVersion
|
2013-12-06 21:37:07 +01:00
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func newUnusedSpace(nBytes int, rfvs ...readerFromVersion) *unusedSpace {
|
2013-12-06 21:37:07 +01:00
|
|
|
return &unusedSpace{
|
|
|
|
nBytes: nBytes,
|
|
|
|
rfvs: rfvs,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
func (u *unusedSpace) readFromVersion(v version, r io.Reader) (int64, error) {
|
2013-12-06 21:37:07 +01:00
|
|
|
var read int64
|
|
|
|
|
|
|
|
for _, rfv := range u.rfvs {
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
n, err := rfv.readFromVersion(v, r)
|
2013-12-06 21:37:07 +01:00
|
|
|
if err != nil {
|
|
|
|
return read + n, err
|
|
|
|
}
|
|
|
|
read += n
|
|
|
|
if read > int64(u.nBytes) {
|
|
|
|
return read, errors.New("read too much from armory's unused space")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read rest of actually unused bytes.
|
|
|
|
unused := make([]byte, u.nBytes-int(read))
|
2014-04-16 23:22:39 +02:00
|
|
|
n, err := io.ReadFull(r, unused)
|
2013-12-06 21:37:07 +01:00
|
|
|
return read + int64(n), err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *unusedSpace) WriteTo(w io.Writer) (int64, error) {
|
|
|
|
var written int64
|
|
|
|
|
|
|
|
for _, wt := range u.rfvs {
|
|
|
|
n, err := wt.WriteTo(w)
|
|
|
|
if err != nil {
|
|
|
|
return written + n, err
|
|
|
|
}
|
|
|
|
written += n
|
|
|
|
if written > int64(u.nBytes) {
|
|
|
|
return written, errors.New("wrote too much to armory's unused space")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write rest of actually unused bytes.
|
|
|
|
unused := make([]byte, u.nBytes-int(written))
|
|
|
|
n, err := w.Write(unused)
|
|
|
|
return written + int64(n), err
|
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// walletAddress is the internal interface used to abstracted around the
|
|
|
|
// different address types.
|
2014-03-11 02:28:40 +01:00
|
|
|
type walletAddress interface {
|
|
|
|
io.ReaderFrom
|
|
|
|
io.WriterTo
|
2014-04-09 02:18:52 +02:00
|
|
|
WalletAddress
|
2014-07-08 20:17:24 +02:00
|
|
|
watchingCopy(*Store) walletAddress
|
2014-03-27 16:32:56 +01:00
|
|
|
setSyncStatus(SyncStatus)
|
2014-03-11 02:28:40 +01:00
|
|
|
}
|
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
type btcAddress struct {
|
2014-07-08 20:17:24 +02:00
|
|
|
store *Store
|
2014-04-09 02:18:52 +02:00
|
|
|
address btcutil.Address
|
2014-03-27 16:32:56 +01:00
|
|
|
flags addrFlags
|
|
|
|
chaincode [32]byte
|
|
|
|
chainIndex int64
|
|
|
|
chainDepth int64 // unused
|
|
|
|
initVector [16]byte
|
|
|
|
privKey [32]byte
|
2014-04-09 02:18:52 +02:00
|
|
|
pubKey *btcec.PublicKey
|
2014-03-27 16:32:56 +01:00
|
|
|
firstSeen int64
|
|
|
|
lastSeen int64
|
|
|
|
firstBlock int32
|
|
|
|
partialSyncHeight int32 // This is reappropriated from armory's `lastBlock` field.
|
|
|
|
privKeyCT []byte // non-nil if unlocked.
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2013-11-20 02:18:11 +01:00
|
|
|
const (
|
|
|
|
// Root address has a chain index of -1. Each subsequent
|
|
|
|
// chained address increments the index.
|
|
|
|
rootKeyChainIdx = -1
|
|
|
|
|
|
|
|
// Imported private keys are not part of the chain, and have a
|
|
|
|
// special index of -2.
|
|
|
|
importedKeyChainIdx = -2
|
|
|
|
)
|
|
|
|
|
2013-11-04 17:50:32 +01:00
|
|
|
const (
|
|
|
|
pubkeyCompressed byte = 0x2
|
|
|
|
pubkeyUncompressed byte = 0x4
|
|
|
|
)
|
|
|
|
|
|
|
|
type publicKey []byte
|
|
|
|
|
|
|
|
func (k *publicKey) ReadFrom(r io.Reader) (n int64, err error) {
|
|
|
|
var read int64
|
|
|
|
var format byte
|
|
|
|
read, err = binaryRead(r, binary.LittleEndian, &format)
|
|
|
|
if err != nil {
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
|
|
|
|
// Remove the oddness from the format
|
|
|
|
noodd := format
|
|
|
|
noodd &= ^byte(0x1)
|
|
|
|
|
|
|
|
var s []byte
|
|
|
|
switch noodd {
|
|
|
|
case pubkeyUncompressed:
|
|
|
|
// Read the remaining 64 bytes.
|
|
|
|
s = make([]byte, 64)
|
|
|
|
|
|
|
|
case pubkeyCompressed:
|
|
|
|
// Read the remaining 32 bytes.
|
|
|
|
s = make([]byte, 32)
|
|
|
|
|
|
|
|
default:
|
|
|
|
return n, errors.New("unrecognized pubkey format")
|
|
|
|
}
|
|
|
|
|
|
|
|
read, err = binaryRead(r, binary.LittleEndian, &s)
|
|
|
|
if err != nil {
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
|
|
|
|
*k = append([]byte{format}, s...)
|
2021-03-24 14:43:24 +01:00
|
|
|
return // nolint:nakedret
|
2013-11-04 17:50:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (k *publicKey) WriteTo(w io.Writer) (n int64, err error) {
|
|
|
|
return binaryWrite(w, binary.LittleEndian, []byte(*k))
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// PubKeyAddress implements WalletAddress and additionally provides the
|
2014-04-09 02:18:52 +02:00
|
|
|
// pubkey for a pubkey-based address.
|
|
|
|
type PubKeyAddress interface {
|
|
|
|
WalletAddress
|
|
|
|
// PubKey returns the public key associated with the address.
|
|
|
|
PubKey() *btcec.PublicKey
|
|
|
|
// ExportPubKey returns the public key associated with the address
|
|
|
|
// serialised as a hex encoded string.
|
|
|
|
ExportPubKey() string
|
|
|
|
// PrivKey returns the private key for the address.
|
2014-07-08 20:17:24 +02:00
|
|
|
// It can fail if the key store is watching only, the key store is locked,
|
2014-04-09 02:18:52 +02:00
|
|
|
// or the address doesn't have any keys.
|
2014-09-27 20:59:18 +02:00
|
|
|
PrivKey() (*btcec.PrivateKey, error)
|
2014-05-22 00:50:47 +02:00
|
|
|
// ExportPrivKey exports the WIF private key.
|
|
|
|
ExportPrivKey() (*btcutil.WIF, error)
|
2014-04-09 02:18:52 +02:00
|
|
|
}
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
// newBtcAddress initializes and returns a new address. privkey must
|
|
|
|
// be 32 bytes. iv must be 16 bytes, or nil (in which case it is
|
|
|
|
// randomly generated).
|
2014-07-08 20:17:24 +02:00
|
|
|
func newBtcAddress(wallet *Store, privkey, iv []byte, bs *BlockStamp, compressed bool) (addr *btcAddress, err error) {
|
2013-09-03 06:10:32 +02:00
|
|
|
if len(privkey) != 32 {
|
2013-09-09 20:14:57 +02:00
|
|
|
return nil, errors.New("private key is not 32 bytes")
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
addr, err = newBtcAddressWithoutPrivkey(wallet,
|
|
|
|
pubkeyFromPrivkey(privkey, compressed), iv, bs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
2014-04-09 02:18:52 +02:00
|
|
|
|
|
|
|
addr.flags.createPrivKeyNextUnlock = false
|
|
|
|
addr.flags.hasPrivKey = true
|
2014-01-17 01:28:34 +01:00
|
|
|
addr.privKeyCT = privkey
|
2013-09-03 06:10:32 +02:00
|
|
|
|
|
|
|
return addr, nil
|
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
// newBtcAddressWithoutPrivkey initializes and returns a new address with an
|
|
|
|
// unknown (at the time) private key that must be found later. pubkey must be
|
|
|
|
// 33 or 65 bytes, and iv must be 16 bytes or empty (in which case it is
|
|
|
|
// randomly generated).
|
2014-07-08 20:17:24 +02:00
|
|
|
func newBtcAddressWithoutPrivkey(s *Store, pubkey, iv []byte, bs *BlockStamp) (addr *btcAddress, err error) {
|
2014-01-17 01:28:34 +01:00
|
|
|
var compressed bool
|
2014-05-20 15:12:43 +02:00
|
|
|
switch n := len(pubkey); n {
|
|
|
|
case btcec.PubKeyBytesLenCompressed:
|
2014-01-17 01:28:34 +01:00
|
|
|
compressed = true
|
2014-05-20 15:12:43 +02:00
|
|
|
case btcec.PubKeyBytesLenUncompressed:
|
2014-01-17 01:28:34 +01:00
|
|
|
compressed = false
|
|
|
|
default:
|
2014-05-20 15:12:43 +02:00
|
|
|
return nil, fmt.Errorf("invalid pubkey length %d", n)
|
2014-01-17 01:28:34 +01:00
|
|
|
}
|
|
|
|
if len(iv) == 0 {
|
|
|
|
iv = make([]byte, 16)
|
|
|
|
if _, err := rand.Read(iv); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else if len(iv) != 16 {
|
|
|
|
return nil, errors.New("init vector must be nil or 16 bytes large")
|
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
pk, err := btcec.ParsePubKey(pubkey, btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
address, err := btcutil.NewAddressPubKeyHash(btcutil.Hash160(pubkey), s.netParams())
|
2014-04-09 02:18:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
addr = &btcAddress{
|
|
|
|
flags: addrFlags{
|
|
|
|
hasPrivKey: false,
|
|
|
|
hasPubKey: true,
|
2014-02-03 16:21:47 +01:00
|
|
|
encrypted: false,
|
2014-01-17 01:28:34 +01:00
|
|
|
createPrivKeyNextUnlock: true,
|
|
|
|
compressed: compressed,
|
2014-02-03 16:21:47 +01:00
|
|
|
change: false,
|
2014-03-17 15:24:14 +01:00
|
|
|
unsynced: false,
|
2014-01-17 01:28:34 +01:00
|
|
|
},
|
2014-07-08 20:17:24 +02:00
|
|
|
store: s,
|
2014-04-09 02:18:52 +02:00
|
|
|
address: address,
|
2014-01-17 01:28:34 +01:00
|
|
|
firstSeen: time.Now().Unix(),
|
|
|
|
firstBlock: bs.Height,
|
2014-04-09 02:18:52 +02:00
|
|
|
pubKey: pk,
|
2014-01-17 01:28:34 +01:00
|
|
|
}
|
|
|
|
copy(addr.initVector[:], iv)
|
|
|
|
|
|
|
|
return addr, nil
|
|
|
|
}
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
// newRootBtcAddress generates a new address, also setting the
|
|
|
|
// chaincode and chain index to represent this address as a root
|
|
|
|
// address.
|
2014-07-08 20:17:24 +02:00
|
|
|
func newRootBtcAddress(s *Store, privKey, iv, chaincode []byte,
|
2013-11-20 02:18:11 +01:00
|
|
|
bs *BlockStamp) (addr *btcAddress, err error) {
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
if len(chaincode) != 32 {
|
2013-09-09 20:14:57 +02:00
|
|
|
return nil, errors.New("chaincode is not 32 bytes")
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2013-11-20 02:18:11 +01:00
|
|
|
// Create new btcAddress with provided inputs. This will
|
|
|
|
// always use a compressed pubkey.
|
2014-07-08 20:17:24 +02:00
|
|
|
addr, err = newBtcAddress(s, privKey, iv, bs, true)
|
2013-09-03 06:10:32 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
copy(addr.chaincode[:], chaincode)
|
2013-11-20 02:18:11 +01:00
|
|
|
addr.chainIndex = rootKeyChainIdx
|
2013-09-03 06:10:32 +02:00
|
|
|
|
|
|
|
return addr, err
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2013-12-03 18:33:37 +01:00
|
|
|
// verifyKeypairs creates a signature using the parsed private key and
|
|
|
|
// verifies the signature with the parsed public key. If either of these
|
|
|
|
// steps fail, the keypair generation failed and any funds sent to this
|
|
|
|
// address will be unspendable. This step requires an unencrypted or
|
|
|
|
// unlocked btcAddress.
|
|
|
|
func (a *btcAddress) verifyKeypairs() error {
|
2014-01-17 01:28:34 +01:00
|
|
|
if len(a.privKeyCT) != 32 {
|
2013-12-03 18:33:37 +01:00
|
|
|
return errors.New("private key unavailable")
|
|
|
|
}
|
|
|
|
|
2014-09-27 20:59:18 +02:00
|
|
|
privKey := &btcec.PrivateKey{
|
2014-04-09 02:18:52 +02:00
|
|
|
PublicKey: *a.pubKey.ToECDSA(),
|
2014-01-17 01:28:34 +01:00
|
|
|
D: new(big.Int).SetBytes(a.privKeyCT),
|
2013-12-03 18:45:27 +01:00
|
|
|
}
|
2013-12-03 18:33:37 +01:00
|
|
|
|
|
|
|
data := "String to sign."
|
2014-09-27 20:59:18 +02:00
|
|
|
sig, err := privKey.Sign([]byte(data))
|
2013-12-03 18:33:37 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2014-09-27 20:59:18 +02:00
|
|
|
ok := sig.Verify([]byte(data), privKey.PubKey())
|
2013-12-03 18:33:37 +01:00
|
|
|
if !ok {
|
2014-09-27 20:59:18 +02:00
|
|
|
return errors.New("pubkey verification failed")
|
2013-12-03 18:33:37 +01:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
// ReadFrom reads an encrypted address from an io.Reader.
|
2013-09-09 20:14:57 +02:00
|
|
|
func (a *btcAddress) ReadFrom(r io.Reader) (n int64, err error) {
|
2013-08-21 16:37:30 +02:00
|
|
|
var read int64
|
|
|
|
|
|
|
|
// Checksums
|
|
|
|
var chkPubKeyHash uint32
|
|
|
|
var chkChaincode uint32
|
|
|
|
var chkInitVector uint32
|
|
|
|
var chkPrivKey uint32
|
|
|
|
var chkPubKey uint32
|
2014-04-09 02:18:52 +02:00
|
|
|
var pubKeyHash [ripemd160.Size]byte
|
|
|
|
var pubKey publicKey
|
2013-08-21 16:37:30 +02:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Read serialized key store into addr fields and checksums.
|
2013-08-21 16:37:30 +02:00
|
|
|
datas := []interface{}{
|
2014-04-09 02:18:52 +02:00
|
|
|
&pubKeyHash,
|
2013-08-21 16:37:30 +02:00
|
|
|
&chkPubKeyHash,
|
2013-09-03 06:10:32 +02:00
|
|
|
make([]byte, 4), // version
|
2013-09-09 20:14:57 +02:00
|
|
|
&a.flags,
|
|
|
|
&a.chaincode,
|
2013-08-21 16:37:30 +02:00
|
|
|
&chkChaincode,
|
2013-09-09 20:14:57 +02:00
|
|
|
&a.chainIndex,
|
|
|
|
&a.chainDepth,
|
|
|
|
&a.initVector,
|
2013-08-21 16:37:30 +02:00
|
|
|
&chkInitVector,
|
2013-09-09 20:14:57 +02:00
|
|
|
&a.privKey,
|
2013-08-21 16:37:30 +02:00
|
|
|
&chkPrivKey,
|
2014-04-09 02:18:52 +02:00
|
|
|
&pubKey,
|
2013-08-21 16:37:30 +02:00
|
|
|
&chkPubKey,
|
2013-09-09 20:14:57 +02:00
|
|
|
&a.firstSeen,
|
|
|
|
&a.lastSeen,
|
|
|
|
&a.firstBlock,
|
2014-03-27 16:32:56 +01:00
|
|
|
&a.partialSyncHeight,
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
for _, data := range datas {
|
2013-09-03 06:10:32 +02:00
|
|
|
if rf, ok := data.(io.ReaderFrom); ok {
|
|
|
|
read, err = rf.ReadFrom(r)
|
|
|
|
} else {
|
|
|
|
read, err = binaryRead(r, binary.LittleEndian, data)
|
|
|
|
}
|
|
|
|
if err != nil {
|
2013-08-21 16:37:30 +02:00
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify checksums, correct errors where possible.
|
|
|
|
checks := []struct {
|
|
|
|
data []byte
|
|
|
|
chk uint32
|
|
|
|
}{
|
2014-04-09 02:18:52 +02:00
|
|
|
{pubKeyHash[:], chkPubKeyHash},
|
2013-09-09 20:14:57 +02:00
|
|
|
{a.chaincode[:], chkChaincode},
|
|
|
|
{a.initVector[:], chkInitVector},
|
|
|
|
{a.privKey[:], chkPrivKey},
|
2014-04-09 02:18:52 +02:00
|
|
|
{pubKey, chkPubKey},
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
2013-09-09 20:14:57 +02:00
|
|
|
for i := range checks {
|
2013-08-21 16:37:30 +02:00
|
|
|
if err = verifyAndFix(checks[i].data, checks[i].chk); err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
if !a.flags.hasPubKey {
|
|
|
|
return n, errors.New("read in an address without a public key")
|
|
|
|
}
|
|
|
|
pk, err := btcec.ParsePubKey(pubKey, btcec.S256())
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
a.pubKey = pk
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash[:], a.store.netParams())
|
2014-04-09 02:18:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
a.address = addr
|
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
2013-09-09 20:14:57 +02:00
|
|
|
func (a *btcAddress) WriteTo(w io.Writer) (n int64, err error) {
|
2013-08-21 16:37:30 +02:00
|
|
|
var written int64
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
pubKey := a.pubKeyBytes()
|
2014-04-09 02:18:52 +02:00
|
|
|
|
|
|
|
hash := a.address.ScriptAddress()
|
2013-08-21 16:37:30 +02:00
|
|
|
datas := []interface{}{
|
2014-04-09 02:18:52 +02:00
|
|
|
&hash,
|
|
|
|
walletHash(hash),
|
2013-09-03 06:10:32 +02:00
|
|
|
make([]byte, 4), //version
|
2013-09-09 20:14:57 +02:00
|
|
|
&a.flags,
|
|
|
|
&a.chaincode,
|
|
|
|
walletHash(a.chaincode[:]),
|
|
|
|
&a.chainIndex,
|
|
|
|
&a.chainDepth,
|
|
|
|
&a.initVector,
|
|
|
|
walletHash(a.initVector[:]),
|
|
|
|
&a.privKey,
|
|
|
|
walletHash(a.privKey[:]),
|
2014-04-09 02:18:52 +02:00
|
|
|
&pubKey,
|
|
|
|
walletHash(pubKey),
|
2013-09-09 20:14:57 +02:00
|
|
|
&a.firstSeen,
|
|
|
|
&a.lastSeen,
|
|
|
|
&a.firstBlock,
|
2014-03-27 16:32:56 +01:00
|
|
|
&a.partialSyncHeight,
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
for _, data := range datas {
|
2013-09-03 06:10:32 +02:00
|
|
|
if wt, ok := data.(io.WriterTo); ok {
|
|
|
|
written, err = wt.WriteTo(w)
|
|
|
|
} else {
|
|
|
|
written, err = binaryWrite(w, binary.LittleEndian, data)
|
|
|
|
}
|
2013-08-21 16:37:30 +02:00
|
|
|
if err != nil {
|
|
|
|
return n + written, err
|
|
|
|
}
|
|
|
|
n += written
|
|
|
|
}
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
// encrypt attempts to encrypt an address's clear text private key,
|
|
|
|
// failing if the address is already encrypted or if the private key is
|
|
|
|
// not 32 bytes. If successful, the encryption flag is set.
|
|
|
|
func (a *btcAddress) encrypt(key []byte) error {
|
|
|
|
if a.flags.encrypted {
|
2014-02-04 16:37:28 +01:00
|
|
|
return ErrAlreadyEncrypted
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
2014-01-17 01:28:34 +01:00
|
|
|
if len(a.privKeyCT) != 32 {
|
2013-09-09 20:14:57 +02:00
|
|
|
return errors.New("invalid clear text private key")
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
aesBlockEncrypter, err := aes.NewCipher(key)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
aesEncrypter := cipher.NewCFBEncrypter(aesBlockEncrypter, a.initVector[:])
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
aesEncrypter.XORKeyStream(a.privKey[:], a.privKeyCT)
|
2013-09-03 06:10:32 +02:00
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
a.flags.hasPrivKey = true
|
2013-09-03 06:10:32 +02:00
|
|
|
a.flags.encrypted = true
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// lock removes the reference this address holds to its clear text
|
|
|
|
// private key. This function fails if the address is not encrypted.
|
|
|
|
func (a *btcAddress) lock() error {
|
|
|
|
if !a.flags.encrypted {
|
2013-09-09 20:14:57 +02:00
|
|
|
return errors.New("unable to lock unencrypted address")
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
zero(a.privKeyCT)
|
|
|
|
a.privKeyCT = nil
|
2013-09-03 06:10:32 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-01-17 01:28:34 +01:00
|
|
|
// unlock decrypts and stores a pointer to an address's private key,
|
2013-09-03 06:10:32 +02:00
|
|
|
// failing if the address is not encrypted, or the provided key is
|
2013-11-11 21:30:50 +01:00
|
|
|
// incorrect. 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 *btcAddress) unlock(key []byte) (privKeyCT []byte, err error) {
|
2013-09-03 06:10:32 +02:00
|
|
|
if !a.flags.encrypted {
|
2013-11-11 21:30:50 +01:00
|
|
|
return nil, errors.New("unable to unlock unencrypted address")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decrypt private key with AES key.
|
2013-09-03 06:10:32 +02:00
|
|
|
aesBlockDecrypter, err := aes.NewCipher(key)
|
2013-08-21 16:37:30 +02:00
|
|
|
if err != nil {
|
2013-11-11 21:30:50 +01:00
|
|
|
return nil, err
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
2013-09-03 06:10:32 +02:00
|
|
|
aesDecrypter := cipher.NewCFBDecrypter(aesBlockDecrypter, a.initVector[:])
|
2013-11-11 21:30:50 +01:00
|
|
|
privkey := make([]byte, 32)
|
|
|
|
aesDecrypter.XORKeyStream(privkey, a.privKey[:])
|
2013-08-21 16:37:30 +02:00
|
|
|
|
2014-07-01 17:02:13 +02:00
|
|
|
// If secret is already saved, simply compare the bytes.
|
|
|
|
if len(a.privKeyCT) == 32 {
|
|
|
|
if !bytes.Equal(a.privKeyCT, privkey) {
|
|
|
|
return nil, ErrWrongPassphrase
|
|
|
|
}
|
|
|
|
privKeyCT := make([]byte, 32)
|
|
|
|
copy(privKeyCT, a.privKeyCT)
|
|
|
|
return privKeyCT, nil
|
|
|
|
}
|
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
x, y := btcec.S256().ScalarBaseMult(privkey)
|
2014-04-09 02:18:52 +02:00
|
|
|
if x.Cmp(a.pubKey.X) != 0 || y.Cmp(a.pubKey.Y) != 0 {
|
2014-01-27 15:30:42 +01:00
|
|
|
return nil, ErrWrongPassphrase
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2013-11-11 21:30:50 +01:00
|
|
|
privkeyCopy := make([]byte, 32)
|
|
|
|
copy(privkeyCopy, privkey)
|
2014-01-17 01:28:34 +01:00
|
|
|
a.privKeyCT = privkey
|
2013-11-11 21:30:50 +01:00
|
|
|
return privkeyCopy, nil
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2014-01-27 15:30:42 +01:00
|
|
|
// changeEncryptionKey re-encrypts the private keys for an address
|
|
|
|
// with a new AES encryption key. oldkey must be the old AES encryption key
|
|
|
|
// and is used to decrypt the private key.
|
2013-09-09 20:14:57 +02:00
|
|
|
func (a *btcAddress) changeEncryptionKey(oldkey, newkey []byte) error {
|
2014-01-27 15:30:42 +01:00
|
|
|
// Address must have a private key and be encrypted to continue.
|
|
|
|
if !a.flags.hasPrivKey {
|
|
|
|
return errors.New("no private key")
|
|
|
|
}
|
|
|
|
if !a.flags.encrypted {
|
|
|
|
return errors.New("address is not encrypted")
|
|
|
|
}
|
|
|
|
|
|
|
|
privKeyCT, err := a.unlock(oldkey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
aesBlockEncrypter, err := aes.NewCipher(newkey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
newIV := make([]byte, len(a.initVector))
|
|
|
|
if _, err := rand.Read(newIV); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
copy(a.initVector[:], newIV)
|
|
|
|
aesEncrypter := cipher.NewCFBEncrypter(aesBlockEncrypter, a.initVector[:])
|
|
|
|
aesEncrypter.XORKeyStream(a.privKey[:], privKeyCT)
|
|
|
|
|
|
|
|
return nil
|
2013-09-09 20:14:57 +02:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// Address returns the pub key address, implementing AddressInfo.
|
|
|
|
func (a *btcAddress) Address() btcutil.Address {
|
|
|
|
return a.address
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// AddrHash returns the pub key hash, implementing WalletAddress.
|
|
|
|
func (a *btcAddress) AddrHash() string {
|
|
|
|
return string(a.address.ScriptAddress())
|
|
|
|
}
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// FirstBlock returns the first block the address is seen in, implementing
|
|
|
|
// AddressInfo.
|
|
|
|
func (a *btcAddress) FirstBlock() int32 {
|
|
|
|
return a.firstBlock
|
|
|
|
}
|
|
|
|
|
|
|
|
// Imported returns the pub if the address was imported, or a chained address,
|
|
|
|
// implementing AddressInfo.
|
|
|
|
func (a *btcAddress) Imported() bool {
|
|
|
|
return a.chainIndex == importedKeyChainIdx
|
|
|
|
}
|
|
|
|
|
2014-09-23 12:36:49 +02:00
|
|
|
// Change returns true if the address was created as a change address,
|
2014-04-09 02:18:52 +02:00
|
|
|
// implementing AddressInfo.
|
|
|
|
func (a *btcAddress) Change() bool {
|
|
|
|
return a.flags.change
|
|
|
|
}
|
|
|
|
|
2014-09-23 12:36:49 +02:00
|
|
|
// Compressed returns true if the address backing key is compressed,
|
2014-04-09 02:18:52 +02:00
|
|
|
// implementing AddressInfo.
|
|
|
|
func (a *btcAddress) Compressed() bool {
|
|
|
|
return a.flags.compressed
|
|
|
|
}
|
|
|
|
|
|
|
|
// SyncStatus returns a SyncStatus type for how the address is currently
|
|
|
|
// synced. For an Unsynced type, the value is the recorded first seen
|
|
|
|
// block height of the address.
|
|
|
|
func (a *btcAddress) SyncStatus() SyncStatus {
|
|
|
|
switch {
|
|
|
|
case a.flags.unsynced && !a.flags.partialSync:
|
|
|
|
return Unsynced(a.firstBlock)
|
|
|
|
case a.flags.unsynced && a.flags.partialSync:
|
|
|
|
return PartialSync(a.partialSyncHeight)
|
|
|
|
default:
|
|
|
|
return FullSync{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PubKey returns the hex encoded pubkey for the address. Implementing
|
|
|
|
// PubKeyAddress.
|
|
|
|
func (a *btcAddress) PubKey() *btcec.PublicKey {
|
|
|
|
return a.pubKey
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *btcAddress) pubKeyBytes() []byte {
|
|
|
|
if a.Compressed() {
|
|
|
|
return a.pubKey.SerializeCompressed()
|
|
|
|
}
|
2014-07-08 20:17:24 +02:00
|
|
|
return a.pubKey.SerializeUncompressed()
|
2014-04-09 02:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ExportPubKey returns the public key associated with the address serialised as
|
|
|
|
// a hex encoded string. Implemnts PubKeyAddress
|
|
|
|
func (a *btcAddress) ExportPubKey() string {
|
|
|
|
return hex.EncodeToString(a.pubKeyBytes())
|
|
|
|
}
|
|
|
|
|
2014-04-11 20:52:50 +02:00
|
|
|
// PrivKey implements PubKeyAddress by returning the private key, or an error
|
2014-07-08 20:17:24 +02:00
|
|
|
// if the key store is locked, watching only or the private key is missing.
|
2014-09-27 20:59:18 +02:00
|
|
|
func (a *btcAddress) PrivKey() (*btcec.PrivateKey, error) {
|
2014-07-08 20:17:24 +02:00
|
|
|
if a.store.flags.watchingOnly {
|
|
|
|
return nil, ErrWatchingOnly
|
2014-04-09 02:18:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !a.flags.hasPrivKey {
|
|
|
|
return nil, errors.New("no private key for address")
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Key store must be unlocked to decrypt the private key.
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
if a.store.isLocked() {
|
2014-07-08 20:17:24 +02:00
|
|
|
return nil, ErrLocked
|
2014-04-09 02:18:52 +02:00
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Unlock address with key store secret. unlock returns a copy of
|
2014-04-09 02:18:52 +02:00
|
|
|
// the clear text private key, and may be used safely even
|
|
|
|
// during an address lock.
|
2014-07-08 20:17:24 +02:00
|
|
|
privKeyCT, err := a.unlock(a.store.secret)
|
2014-04-09 02:18:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-09-27 20:59:18 +02:00
|
|
|
return &btcec.PrivateKey{
|
2014-04-09 02:18:52 +02:00
|
|
|
PublicKey: *a.pubKey.ToECDSA(),
|
|
|
|
D: new(big.Int).SetBytes(privKeyCT),
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2014-05-22 00:50:47 +02:00
|
|
|
// ExportPrivKey exports the private key as a WIF for encoding as a string
|
|
|
|
// in the Wallet Import Formt.
|
|
|
|
func (a *btcAddress) ExportPrivKey() (*btcutil.WIF, error) {
|
2014-04-09 02:18:52 +02:00
|
|
|
pk, err := a.PrivKey()
|
|
|
|
if err != nil {
|
2014-05-22 00:50:47 +02:00
|
|
|
return nil, err
|
2014-04-09 02:18:52 +02:00
|
|
|
}
|
2014-05-27 19:50:51 +02:00
|
|
|
// NewWIF only errors if the network is nil. In this case, panic,
|
|
|
|
// as our program's assumptions are so broken that this needs to be
|
|
|
|
// caught immediately, and a stack trace here is more useful than
|
|
|
|
// elsewhere.
|
2021-03-24 14:43:24 +01:00
|
|
|
wif, err := btcutil.NewWIF(pk, a.store.netParams(), a.Compressed())
|
2014-05-27 19:50:51 +02:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return wif, nil
|
2014-04-09 02:18:52 +02:00
|
|
|
}
|
|
|
|
|
2014-01-20 18:56:27 +01:00
|
|
|
// watchingCopy creates a copy of an address without a private key.
|
2014-07-08 20:17:24 +02:00
|
|
|
// This is used to fill a watching a key store with addresses from a
|
|
|
|
// normal key store.
|
|
|
|
func (a *btcAddress) watchingCopy(s *Store) walletAddress {
|
2014-01-20 18:56:27 +01:00
|
|
|
return &btcAddress{
|
2014-07-08 20:17:24 +02:00
|
|
|
store: s,
|
2014-04-09 02:18:52 +02:00
|
|
|
address: a.address,
|
2014-01-20 18:56:27 +01:00
|
|
|
flags: addrFlags{
|
|
|
|
hasPrivKey: false,
|
2014-04-09 02:18:52 +02:00
|
|
|
hasPubKey: true,
|
2014-01-20 18:56:27 +01:00
|
|
|
encrypted: false,
|
|
|
|
createPrivKeyNextUnlock: false,
|
|
|
|
compressed: a.flags.compressed,
|
2014-02-03 16:21:47 +01:00
|
|
|
change: a.flags.change,
|
2014-03-17 15:24:14 +01:00
|
|
|
unsynced: a.flags.unsynced,
|
2014-01-20 18:56:27 +01:00
|
|
|
},
|
2014-03-27 16:32:56 +01:00
|
|
|
chaincode: a.chaincode,
|
|
|
|
chainIndex: a.chainIndex,
|
|
|
|
chainDepth: a.chainDepth,
|
|
|
|
pubKey: a.pubKey,
|
|
|
|
firstSeen: a.firstSeen,
|
|
|
|
lastSeen: a.lastSeen,
|
|
|
|
firstBlock: a.firstBlock,
|
|
|
|
partialSyncHeight: a.partialSyncHeight,
|
2014-01-20 18:56:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-27 16:32:56 +01:00
|
|
|
// setSyncStatus sets the address flags and possibly the partial sync height
|
|
|
|
// depending on the type of s.
|
|
|
|
func (a *btcAddress) setSyncStatus(s SyncStatus) {
|
|
|
|
switch e := s.(type) {
|
|
|
|
case Unsynced:
|
|
|
|
a.flags.unsynced = true
|
|
|
|
a.flags.partialSync = false
|
|
|
|
a.partialSyncHeight = 0
|
|
|
|
|
|
|
|
case PartialSync:
|
|
|
|
a.flags.unsynced = true
|
|
|
|
a.flags.partialSync = true
|
|
|
|
a.partialSyncHeight = int32(e)
|
|
|
|
|
|
|
|
case FullSync:
|
|
|
|
a.flags.unsynced = false
|
|
|
|
a.flags.partialSync = false
|
|
|
|
a.partialSyncHeight = 0
|
|
|
|
}
|
2014-03-17 15:24:14 +01:00
|
|
|
}
|
|
|
|
|
2014-03-13 20:13:39 +01:00
|
|
|
// note that there is no encrypted bit here since if we had a script encrypted
|
|
|
|
// and then used it on the blockchain this provides a simple known plaintext in
|
2014-07-08 20:17:24 +02:00
|
|
|
// the key store file. It was determined that the script in a p2sh transaction is
|
2014-03-13 20:13:39 +01:00
|
|
|
// not a secret and any sane situation would also require a signature (which
|
|
|
|
// does have a secret).
|
|
|
|
type scriptFlags struct {
|
2014-03-27 16:32:56 +01:00
|
|
|
hasScript bool
|
|
|
|
change bool
|
|
|
|
unsynced bool
|
|
|
|
partialSync bool
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ReadFrom implements the io.ReaderFrom interface by reading from r into sf.
|
|
|
|
func (sf *scriptFlags) ReadFrom(r io.Reader) (int64, error) {
|
|
|
|
var b [8]byte
|
2014-04-16 23:22:39 +02:00
|
|
|
n, err := io.ReadFull(r, b[:])
|
2014-03-13 20:13:39 +01:00
|
|
|
if err != nil {
|
|
|
|
return int64(n), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// We match bits from addrFlags for similar fields. hence hasScript uses
|
|
|
|
// the same bit as hasPubKey and the change bit is the same for both.
|
|
|
|
sf.hasScript = b[0]&(1<<1) != 0
|
|
|
|
sf.change = b[0]&(1<<5) != 0
|
2014-03-17 15:24:14 +01:00
|
|
|
sf.unsynced = b[0]&(1<<6) != 0
|
2014-03-27 16:32:56 +01:00
|
|
|
sf.partialSync = b[0]&(1<<7) != 0
|
2014-03-13 20:13:39 +01:00
|
|
|
|
|
|
|
return int64(n), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteTo implements the io.WriteTo interface by writing sf into w.
|
|
|
|
func (sf *scriptFlags) WriteTo(w io.Writer) (int64, error) {
|
|
|
|
var b [8]byte
|
|
|
|
if sf.hasScript {
|
|
|
|
b[0] |= 1 << 1
|
|
|
|
}
|
|
|
|
if sf.change {
|
|
|
|
b[0] |= 1 << 5
|
|
|
|
}
|
2014-03-17 15:24:14 +01:00
|
|
|
if sf.unsynced {
|
|
|
|
b[0] |= 1 << 6
|
|
|
|
}
|
2014-03-27 16:32:56 +01:00
|
|
|
if sf.partialSync {
|
|
|
|
b[0] |= 1 << 7
|
|
|
|
}
|
2014-03-13 20:13:39 +01:00
|
|
|
|
|
|
|
n, err := w.Write(b[:])
|
|
|
|
return int64(n), err
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// p2SHScript represents the variable length script entry in a key store.
|
2014-03-13 20:13:39 +01:00
|
|
|
type p2SHScript []byte
|
|
|
|
|
|
|
|
// ReadFrom implements the ReaderFrom interface by reading the P2SH script from
|
|
|
|
// r in the format <4 bytes little endian length><script bytes>
|
|
|
|
func (a *p2SHScript) ReadFrom(r io.Reader) (n int64, err error) {
|
|
|
|
//read length
|
2014-04-16 23:22:39 +02:00
|
|
|
var lenBytes [4]byte
|
2014-03-13 20:13:39 +01:00
|
|
|
|
2014-04-16 23:22:39 +02:00
|
|
|
read, err := io.ReadFull(r, lenBytes[:])
|
2014-03-13 20:13:39 +01:00
|
|
|
n += int64(read)
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
2014-04-16 23:22:39 +02:00
|
|
|
length := binary.LittleEndian.Uint32(lenBytes[:])
|
2014-03-13 20:13:39 +01:00
|
|
|
|
|
|
|
script := make([]byte, length)
|
|
|
|
|
2014-04-16 23:22:39 +02:00
|
|
|
read, err = io.ReadFull(r, script)
|
2014-03-13 20:13:39 +01:00
|
|
|
n += int64(read)
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
*a = script
|
|
|
|
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteTo implements the WriterTo interface by writing the P2SH script to w in
|
|
|
|
// the format <4 bytes little endian length><script bytes>
|
|
|
|
func (a *p2SHScript) WriteTo(w io.Writer) (n int64, err error) {
|
|
|
|
// Prepare and write 32-bit little-endian length header
|
2014-04-16 23:22:39 +02:00
|
|
|
var lenBytes [4]byte
|
|
|
|
binary.LittleEndian.PutUint32(lenBytes[:], uint32(len(*a)))
|
2014-03-13 20:13:39 +01:00
|
|
|
|
2014-04-16 23:22:39 +02:00
|
|
|
written, err := w.Write(lenBytes[:])
|
2014-03-13 20:13:39 +01:00
|
|
|
n += int64(written)
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now write the bytes themselves.
|
|
|
|
written, err = w.Write(*a)
|
|
|
|
|
|
|
|
return n + int64(written), err
|
|
|
|
}
|
|
|
|
|
|
|
|
type scriptAddress struct {
|
2014-07-08 20:17:24 +02:00
|
|
|
store *Store
|
2014-04-09 02:18:52 +02:00
|
|
|
address btcutil.Address
|
2015-01-30 19:31:29 +01:00
|
|
|
class txscript.ScriptClass
|
2014-04-09 02:18:52 +02:00
|
|
|
addresses []btcutil.Address
|
|
|
|
reqSigs int
|
2014-03-27 16:32:56 +01:00
|
|
|
flags scriptFlags
|
|
|
|
script p2SHScript // variable length
|
|
|
|
firstSeen int64
|
|
|
|
lastSeen int64
|
|
|
|
firstBlock int32
|
|
|
|
partialSyncHeight int32
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// ScriptAddress is an interface representing a Pay-to-Script-Hash style of
|
|
|
|
// bitcoind address.
|
|
|
|
type ScriptAddress interface {
|
|
|
|
WalletAddress
|
|
|
|
// Returns the script associated with the address.
|
|
|
|
Script() []byte
|
|
|
|
// Returns the class of the script associated with the address.
|
2015-01-30 19:31:29 +01:00
|
|
|
ScriptClass() txscript.ScriptClass
|
2014-04-09 02:18:52 +02:00
|
|
|
// Returns the addresses that are required to sign transactions from the
|
|
|
|
// script address.
|
|
|
|
Addresses() []btcutil.Address
|
|
|
|
// Returns the number of signatures required by the script address.
|
|
|
|
RequiredSigs() int
|
|
|
|
}
|
|
|
|
|
2014-03-13 20:13:39 +01:00
|
|
|
// newScriptAddress initializes and returns a new P2SH address.
|
|
|
|
// iv must be 16 bytes, or nil (in which case it is randomly generated).
|
2014-07-08 20:17:24 +02:00
|
|
|
func newScriptAddress(s *Store, script []byte, bs *BlockStamp) (addr *scriptAddress, err error) {
|
2014-04-09 02:18:52 +02:00
|
|
|
class, addresses, reqSigs, err :=
|
2015-01-30 19:31:29 +01:00
|
|
|
txscript.ExtractPkScriptAddrs(script, s.netParams())
|
2014-04-09 02:18:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
scriptHash := btcutil.Hash160(script)
|
|
|
|
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
address, err := btcutil.NewAddressScriptHashFromHash(scriptHash, s.netParams())
|
2014-04-09 02:18:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-03-13 20:13:39 +01:00
|
|
|
addr = &scriptAddress{
|
2014-07-08 20:17:24 +02:00
|
|
|
store: s,
|
2014-04-09 02:18:52 +02:00
|
|
|
address: address,
|
|
|
|
addresses: addresses,
|
|
|
|
class: class,
|
|
|
|
reqSigs: reqSigs,
|
2014-03-13 20:13:39 +01:00
|
|
|
flags: scriptFlags{
|
|
|
|
hasScript: true,
|
|
|
|
change: false,
|
|
|
|
},
|
|
|
|
script: script,
|
|
|
|
firstSeen: time.Now().Unix(),
|
|
|
|
firstBlock: bs.Height,
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadFrom reads an script address from an io.Reader.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (sa *scriptAddress) ReadFrom(r io.Reader) (n int64, err error) {
|
2014-03-13 20:13:39 +01:00
|
|
|
var read int64
|
|
|
|
|
|
|
|
// Checksums
|
|
|
|
var chkScriptHash uint32
|
|
|
|
var chkScript uint32
|
2014-04-09 02:18:52 +02:00
|
|
|
var scriptHash [ripemd160.Size]byte
|
2014-03-13 20:13:39 +01:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
// Read serialized key store into addr fields and checksums.
|
2014-03-13 20:13:39 +01:00
|
|
|
datas := []interface{}{
|
2014-04-09 02:18:52 +02:00
|
|
|
&scriptHash,
|
2014-03-13 20:13:39 +01:00
|
|
|
&chkScriptHash,
|
|
|
|
make([]byte, 4), // version
|
2014-07-08 20:17:24 +02:00
|
|
|
&sa.flags,
|
|
|
|
&sa.script,
|
2014-03-13 20:13:39 +01:00
|
|
|
&chkScript,
|
2014-07-08 20:17:24 +02:00
|
|
|
&sa.firstSeen,
|
|
|
|
&sa.lastSeen,
|
|
|
|
&sa.firstBlock,
|
|
|
|
&sa.partialSyncHeight,
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
for _, data := range datas {
|
|
|
|
if rf, ok := data.(io.ReaderFrom); ok {
|
|
|
|
read, err = rf.ReadFrom(r)
|
|
|
|
} else {
|
|
|
|
read, err = binaryRead(r, binary.LittleEndian, data)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify checksums, correct errors where possible.
|
|
|
|
checks := []struct {
|
|
|
|
data []byte
|
|
|
|
chk uint32
|
|
|
|
}{
|
2014-04-09 02:18:52 +02:00
|
|
|
{scriptHash[:], chkScriptHash},
|
2014-07-08 20:17:24 +02:00
|
|
|
{sa.script, chkScript},
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
for i := range checks {
|
|
|
|
if err = verifyAndFix(checks[i].data, checks[i].chk); err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
address, err := btcutil.NewAddressScriptHashFromHash(scriptHash[:],
|
Remove account support, fix races on btcd connect.
This commit is the result of several big changes being made to the
wallet. In particular, the "handshake" (initial sync to the chain
server) was quite racy and required proper synchronization. To make
fixing this race easier, several other changes were made to the
internal wallet data structures and much of the RPC server ended up
being rewritten.
First, all account support has been removed. The previous Account
struct has been replaced with a Wallet structure, which includes a
keystore for saving keys, and a txstore for storing relevant
transactions. This decision has been made since it is the opinion of
myself and other developers that bitcoind accounts are fundamentally
broken (as accounts implemented by bitcoind support both arbitrary
address groupings as well as moving balances between accounts -- these
are fundamentally incompatible features), and since a BIP0032 keystore
is soon planned to be implemented (at which point, "accounts" can
return as HD extended keys). With the keystore handling the grouping
of related keys, there is no reason have many different Account
structs, and the AccountManager has been removed as well. All RPC
handlers that take an account option will only work with "" (the
default account) or "*" if the RPC allows specifying all accounts.
Second, much of the RPC server has been cleaned up. The global
variables for the RPC server and chain server client have been moved
to part of the rpcServer struct, and the handlers for each RPC method
that are looked up change depending on which components have been set.
Passthrough requests are also no longer handled specially, but when
the chain server is set, a handler to perform the passthrough will be
returned if the method is not otherwise a wallet RPC. The
notification system for websocket clients has also been rewritten so
wallet components can send notifications through channels, rather than
requiring direct access to the RPC server itself, or worse still,
sending directly to a websocket client's send channel. In the future,
this will enable proper registration of notifications, rather than
unsolicited broadcasts to every connected websocket client (see
issue #84).
Finally, and the main reason why much of this cleanup was necessary,
the races during intial sync with the chain server have been fixed.
Previously, when the 'Handshake' was run, a rescan would occur which
would perform modifications to Account data structures as
notifications were received. Synchronization was provided with a
single binary semaphore which serialized all access to wallet and
account data. However, the Handshake itself was not able to run with
this lock (or else notifications would block), and many data races
would occur as both notifications were being handled. If GOMAXPROCS
was ever increased beyond 1, btcwallet would always immediately crash
due to invalid addresses caused by the data races on startup. To fix
this, the single lock for all wallet access has been replaced with
mutexes for both the keystore and txstore. Handling of btcd
notifications and client requests may now occur simultaneously.
GOMAXPROCS has also been set to the number of logical CPUs at the
beginning of main, since with the data races fixed, there's no reason
to prevent the extra parallelism gained by increasing it.
Closes #78.
Closes #101.
Closes #110.
2014-07-09 05:17:38 +02:00
|
|
|
sa.store.netParams())
|
2014-04-09 02:18:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
sa.address = address
|
2014-04-09 02:18:52 +02:00
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
if !sa.flags.hasScript {
|
2014-04-09 02:18:52 +02:00
|
|
|
return n, errors.New("read in an addresss with no script")
|
|
|
|
}
|
|
|
|
|
|
|
|
class, addresses, reqSigs, err :=
|
2015-01-30 19:31:29 +01:00
|
|
|
txscript.ExtractPkScriptAddrs(sa.script, sa.store.netParams())
|
2014-04-09 02:18:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
sa.class = class
|
|
|
|
sa.addresses = addresses
|
|
|
|
sa.reqSigs = reqSigs
|
2014-04-09 02:18:52 +02:00
|
|
|
|
2014-03-13 20:13:39 +01:00
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteTo implements io.WriterTo by writing the scriptAddress to w.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (sa *scriptAddress) WriteTo(w io.Writer) (n int64, err error) {
|
2014-03-13 20:13:39 +01:00
|
|
|
var written int64
|
|
|
|
|
2014-07-08 20:17:24 +02:00
|
|
|
hash := sa.address.ScriptAddress()
|
2014-03-13 20:13:39 +01:00
|
|
|
datas := []interface{}{
|
2014-04-09 02:18:52 +02:00
|
|
|
&hash,
|
|
|
|
walletHash(hash),
|
2014-03-13 20:13:39 +01:00
|
|
|
make([]byte, 4), //version
|
2014-07-08 20:17:24 +02:00
|
|
|
&sa.flags,
|
|
|
|
&sa.script,
|
|
|
|
walletHash(sa.script),
|
|
|
|
&sa.firstSeen,
|
|
|
|
&sa.lastSeen,
|
|
|
|
&sa.firstBlock,
|
|
|
|
&sa.partialSyncHeight,
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
for _, data := range datas {
|
|
|
|
if wt, ok := data.(io.WriterTo); ok {
|
|
|
|
written, err = wt.WriteTo(w)
|
|
|
|
} else {
|
|
|
|
written, err = binaryWrite(w, binary.LittleEndian, data)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return n + written, err
|
|
|
|
}
|
|
|
|
n += written
|
|
|
|
}
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// address returns a btcutil.AddressScriptHash for a btcAddress.
|
2014-04-09 02:18:52 +02:00
|
|
|
func (sa *scriptAddress) Address() btcutil.Address {
|
|
|
|
return sa.address
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// AddrHash returns the script hash, implementing AddressInfo.
|
2014-04-09 02:18:52 +02:00
|
|
|
func (sa *scriptAddress) AddrHash() string {
|
|
|
|
return string(sa.address.ScriptAddress())
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// FirstBlock returns the first blockheight the address is known at.
|
|
|
|
func (sa *scriptAddress) FirstBlock() int32 {
|
|
|
|
return sa.firstBlock
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// Imported currently always returns true since script addresses are always
|
|
|
|
// imported addressed and not part of any chain.
|
|
|
|
func (sa *scriptAddress) Imported() bool {
|
|
|
|
return true
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// Change returns true if the address was created as a change address.
|
|
|
|
func (sa *scriptAddress) Change() bool {
|
|
|
|
return sa.flags.change
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// Compressed returns false since script addresses are never compressed.
|
|
|
|
// Implements WalletAddress.
|
|
|
|
func (sa *scriptAddress) Compressed() bool {
|
2014-03-13 20:13:39 +01:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// Script returns the script that is represented by the address. It should not
|
|
|
|
// be modified.
|
|
|
|
func (sa *scriptAddress) Script() []byte {
|
|
|
|
return sa.script
|
2014-03-27 16:32:56 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// Addresses returns the list of addresses that must sign the script.
|
|
|
|
func (sa *scriptAddress) Addresses() []btcutil.Address {
|
|
|
|
return sa.addresses
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// ScriptClass returns the type of script the address is.
|
2015-01-30 19:31:29 +01:00
|
|
|
func (sa *scriptAddress) ScriptClass() txscript.ScriptClass {
|
2014-04-09 02:18:52 +02:00
|
|
|
return sa.class
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// RequiredSigs returns the number of signatures required by the script.
|
|
|
|
func (sa *scriptAddress) RequiredSigs() int {
|
|
|
|
return sa.reqSigs
|
2014-03-13 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// SyncStatus returns a SyncStatus type for how the address is currently
|
|
|
|
// synced. For an Unsynced type, the value is the recorded first seen
|
|
|
|
// block height of the address.
|
|
|
|
// Implements WalletAddress.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (sa *scriptAddress) SyncStatus() SyncStatus {
|
2014-03-27 16:32:56 +01:00
|
|
|
switch {
|
2014-07-08 20:17:24 +02:00
|
|
|
case sa.flags.unsynced && !sa.flags.partialSync:
|
|
|
|
return Unsynced(sa.firstBlock)
|
|
|
|
case sa.flags.unsynced && sa.flags.partialSync:
|
|
|
|
return PartialSync(sa.partialSyncHeight)
|
2014-03-27 16:32:56 +01:00
|
|
|
default:
|
|
|
|
return FullSync{}
|
|
|
|
}
|
2014-03-17 15:24:14 +01:00
|
|
|
}
|
|
|
|
|
2014-03-27 16:32:56 +01:00
|
|
|
// setSyncStatus sets the address flags and possibly the partial sync height
|
|
|
|
// depending on the type of s.
|
2014-07-08 20:17:24 +02:00
|
|
|
func (sa *scriptAddress) setSyncStatus(s SyncStatus) {
|
2014-03-27 16:32:56 +01:00
|
|
|
switch e := s.(type) {
|
2014-07-08 21:09:58 +02:00
|
|
|
case Unsynced:
|
|
|
|
sa.flags.unsynced = true
|
2014-07-08 20:17:24 +02:00
|
|
|
sa.flags.partialSync = false
|
|
|
|
sa.partialSyncHeight = 0
|
2014-03-27 16:32:56 +01:00
|
|
|
|
|
|
|
case PartialSync:
|
2014-07-08 20:17:24 +02:00
|
|
|
sa.flags.unsynced = true
|
|
|
|
sa.flags.partialSync = true
|
|
|
|
sa.partialSyncHeight = int32(e)
|
2014-03-27 16:32:56 +01:00
|
|
|
|
|
|
|
case FullSync:
|
2014-07-08 20:17:24 +02:00
|
|
|
sa.flags.unsynced = false
|
|
|
|
sa.flags.partialSync = false
|
|
|
|
sa.partialSyncHeight = 0
|
2014-03-27 16:32:56 +01:00
|
|
|
}
|
2014-03-17 15:24:14 +01:00
|
|
|
}
|
|
|
|
|
2014-04-09 02:18:52 +02:00
|
|
|
// watchingCopy creates a copy of an address without a private key.
|
2014-07-08 20:17:24 +02:00
|
|
|
// This is used to fill a watching key store with addresses from a
|
|
|
|
// normal key store.
|
|
|
|
func (sa *scriptAddress) watchingCopy(s *Store) walletAddress {
|
2014-04-09 02:18:52 +02:00
|
|
|
return &scriptAddress{
|
2014-07-08 20:17:24 +02:00
|
|
|
store: s,
|
|
|
|
address: sa.address,
|
|
|
|
addresses: sa.addresses,
|
|
|
|
class: sa.class,
|
|
|
|
reqSigs: sa.reqSigs,
|
2014-04-09 02:18:52 +02:00
|
|
|
flags: scriptFlags{
|
2014-07-08 20:17:24 +02:00
|
|
|
change: sa.flags.change,
|
|
|
|
unsynced: sa.flags.unsynced,
|
2014-04-09 02:18:52 +02:00
|
|
|
},
|
2014-07-08 20:17:24 +02:00
|
|
|
script: sa.script,
|
|
|
|
firstSeen: sa.firstSeen,
|
|
|
|
lastSeen: sa.lastSeen,
|
|
|
|
firstBlock: sa.firstBlock,
|
|
|
|
partialSyncHeight: sa.partialSyncHeight,
|
2014-04-09 02:18:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
func walletHash(b []byte) uint32 {
|
2016-08-08 21:49:09 +02:00
|
|
|
sum := chainhash.DoubleHashB(b)
|
2013-08-21 16:37:30 +02:00
|
|
|
return binary.LittleEndian.Uint32(sum)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(jrick) add error correction.
|
|
|
|
func verifyAndFix(b []byte, chk uint32) error {
|
|
|
|
if walletHash(b) != chk {
|
2013-09-09 20:14:57 +02:00
|
|
|
return ErrChecksumMismatch
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type kdfParameters struct {
|
|
|
|
mem uint64
|
|
|
|
nIter uint32
|
|
|
|
salt [32]byte
|
|
|
|
}
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
// computeKdfParameters returns best guess parameters to the
|
|
|
|
// memory-hard key derivation function to make the computation last
|
|
|
|
// targetSec seconds, while using no more than maxMem bytes of memory.
|
2013-11-15 17:59:37 +01:00
|
|
|
func computeKdfParameters(targetSec float64, maxMem uint64) (*kdfParameters, error) {
|
2013-09-03 06:10:32 +02:00
|
|
|
params := &kdfParameters{}
|
2013-11-15 17:59:37 +01:00
|
|
|
if _, err := rand.Read(params.salt[:]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2013-09-03 06:10:32 +02:00
|
|
|
|
|
|
|
testKey := []byte("This is an example key to test KDF iteration speed")
|
|
|
|
|
|
|
|
memoryReqtBytes := uint64(1024)
|
|
|
|
approxSec := float64(0)
|
|
|
|
|
|
|
|
for approxSec <= targetSec/4 && memoryReqtBytes < maxMem {
|
|
|
|
memoryReqtBytes *= 2
|
|
|
|
before := time.Now()
|
|
|
|
_ = keyOneIter(testKey, params.salt[:], memoryReqtBytes)
|
|
|
|
approxSec = time.Since(before).Seconds()
|
|
|
|
}
|
|
|
|
|
|
|
|
allItersSec := float64(0)
|
|
|
|
nIter := uint32(1)
|
|
|
|
for allItersSec < 0.02 { // This is a magic number straight from armory's source.
|
|
|
|
nIter *= 2
|
|
|
|
before := time.Now()
|
|
|
|
for i := uint32(0); i < nIter; i++ {
|
|
|
|
_ = keyOneIter(testKey, params.salt[:], memoryReqtBytes)
|
|
|
|
}
|
|
|
|
allItersSec = time.Since(before).Seconds()
|
|
|
|
}
|
|
|
|
|
|
|
|
params.mem = memoryReqtBytes
|
|
|
|
params.nIter = nIter
|
|
|
|
|
2013-11-15 17:59:37 +01:00
|
|
|
return params, nil
|
2013-09-03 06:10:32 +02:00
|
|
|
}
|
|
|
|
|
2013-08-21 16:37:30 +02:00
|
|
|
func (params *kdfParameters) WriteTo(w io.Writer) (n int64, err error) {
|
|
|
|
var written int64
|
|
|
|
|
|
|
|
memBytes := make([]byte, 8)
|
|
|
|
nIterBytes := make([]byte, 4)
|
|
|
|
binary.LittleEndian.PutUint64(memBytes, params.mem)
|
|
|
|
binary.LittleEndian.PutUint32(nIterBytes, params.nIter)
|
|
|
|
chkedBytes := append(memBytes, nIterBytes...)
|
|
|
|
chkedBytes = append(chkedBytes, params.salt[:]...)
|
|
|
|
|
|
|
|
datas := []interface{}{
|
|
|
|
¶ms.mem,
|
|
|
|
¶ms.nIter,
|
|
|
|
¶ms.salt,
|
|
|
|
walletHash(chkedBytes),
|
|
|
|
make([]byte, 256-(binary.Size(params)+4)), // padding
|
|
|
|
}
|
|
|
|
for _, data := range datas {
|
|
|
|
if written, err = binaryWrite(w, binary.LittleEndian, data); err != nil {
|
|
|
|
return n + written, err
|
|
|
|
}
|
|
|
|
n += written
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (params *kdfParameters) ReadFrom(r io.Reader) (n int64, err error) {
|
|
|
|
var read int64
|
|
|
|
|
|
|
|
// These must be read in but are not saved directly to params.
|
|
|
|
chkedBytes := make([]byte, 44)
|
|
|
|
var chk uint32
|
|
|
|
padding := make([]byte, 256-(binary.Size(params)+4))
|
|
|
|
|
|
|
|
datas := []interface{}{
|
|
|
|
chkedBytes,
|
|
|
|
&chk,
|
|
|
|
padding,
|
|
|
|
}
|
|
|
|
for _, data := range datas {
|
|
|
|
if read, err = binaryRead(r, binary.LittleEndian, data); err != nil {
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify checksum
|
|
|
|
if err = verifyAndFix(chkedBytes, chk); err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
2013-09-03 06:10:32 +02:00
|
|
|
// Read params
|
2013-08-21 16:37:30 +02:00
|
|
|
buf := bytes.NewBuffer(chkedBytes)
|
|
|
|
datas = []interface{}{
|
|
|
|
¶ms.mem,
|
|
|
|
¶ms.nIter,
|
|
|
|
¶ms.salt,
|
|
|
|
}
|
|
|
|
for _, data := range datas {
|
|
|
|
if err = binary.Read(buf, binary.LittleEndian, data); err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type addrEntry struct {
|
|
|
|
pubKeyHash160 [ripemd160.Size]byte
|
|
|
|
addr btcAddress
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *addrEntry) WriteTo(w io.Writer) (n int64, err error) {
|
|
|
|
var written int64
|
|
|
|
|
|
|
|
// Write header
|
|
|
|
if written, err = binaryWrite(w, binary.LittleEndian, addrHeader); err != nil {
|
|
|
|
return n + written, err
|
|
|
|
}
|
|
|
|
n += written
|
|
|
|
|
|
|
|
// Write hash
|
|
|
|
if written, err = binaryWrite(w, binary.LittleEndian, &e.pubKeyHash160); err != nil {
|
|
|
|
return n + written, err
|
|
|
|
}
|
|
|
|
n += written
|
|
|
|
|
|
|
|
// Write btcAddress
|
|
|
|
written, err = e.addr.WriteTo(w)
|
2013-09-03 06:10:32 +02:00
|
|
|
n += written
|
|
|
|
return n, err
|
2013-08-21 16:37:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e *addrEntry) ReadFrom(r io.Reader) (n int64, err error) {
|
|
|
|
var read int64
|
|
|
|
|
|
|
|
if read, err = binaryRead(r, binary.LittleEndian, &e.pubKeyHash160); err != nil {
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
|
|
|
|
read, err = e.addr.ReadFrom(r)
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
|
2014-03-13 20:13:39 +01:00
|
|
|
// scriptEntry is the entry type for a P2SH script.
|
|
|
|
type scriptEntry struct {
|
|
|
|
scriptHash160 [ripemd160.Size]byte
|
|
|
|
script scriptAddress
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteTo implements io.WriterTo by writing the entry to w.
|
|
|
|
func (e *scriptEntry) WriteTo(w io.Writer) (n int64, err error) {
|
|
|
|
var written int64
|
|
|
|
|
|
|
|
// Write header
|
|
|
|
if written, err = binaryWrite(w, binary.LittleEndian, scriptHeader); err != nil {
|
|
|
|
return n + written, err
|
|
|
|
}
|
|
|
|
n += written
|
|
|
|
|
|
|
|
// Write hash
|
|
|
|
if written, err = binaryWrite(w, binary.LittleEndian, &e.scriptHash160); err != nil {
|
|
|
|
return n + written, err
|
|
|
|
}
|
|
|
|
n += written
|
|
|
|
|
|
|
|
// Write btcAddress
|
|
|
|
written, err = e.script.WriteTo(w)
|
|
|
|
n += written
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadFrom implements io.ReaderFrom by reading the entry from e.
|
|
|
|
func (e *scriptEntry) ReadFrom(r io.Reader) (n int64, err error) {
|
|
|
|
var read int64
|
|
|
|
|
|
|
|
if read, err = binaryRead(r, binary.LittleEndian, &e.scriptHash160); err != nil {
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
n += read
|
|
|
|
|
|
|
|
read, err = e.script.ReadFrom(r)
|
|
|
|
return n + read, err
|
|
|
|
}
|
|
|
|
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
// BlockStamp defines a block (by height and a unique hash) and is
|
2014-07-08 20:17:24 +02:00
|
|
|
// used to mark a point in the blockchain that a key store element is
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
// synced to.
|
|
|
|
type BlockStamp struct {
|
2016-08-08 21:49:09 +02:00
|
|
|
Hash *chainhash.Hash
|
Implement address rescanning.
When a wallet is opened, a rescan request will be sent to btcd with
all active addresses from the wallet, to rescan from the last synced
block (now saved to the wallet file) and the current best block.
As multi-account support is further explored, rescan requests should
be batched together to send a single request for all addresses from
all wallets.
This change introduces several changes to the wallet, tx, and utxo
files. Wallet files are still compatible, however, a rescan will try
to start at the genesis block since no correct "last synced to" or
"created at block X" was saved. The tx and utxo files, however, are
not compatible and should be deleted (or an error will occur on read).
If any errors occur opening the utxo file, a rescan will start
beginning at the creation block saved in the wallet.
2013-10-30 02:22:14 +01:00
|
|
|
Height int32
|
|
|
|
}
|