Make AddressInfo an interface.
Shortly we will add new types of address, so make AddressInfo an interface, with concrete types providing address-specific information. Adapt existing code to this new status quo.
This commit is contained in:
parent
34e4c0be35
commit
df31e30839
5 changed files with 100 additions and 38 deletions
11
account.go
11
account.go
|
@ -315,7 +315,7 @@ func (a *Account) DumpPrivKeys() ([]string, error) {
|
|||
return nil, err
|
||||
}
|
||||
encKey, err := btcutil.EncodePrivateKey(key.D.Bytes(),
|
||||
a.Wallet.Net(), info.Compressed)
|
||||
a.Wallet.Net(), info.Compressed())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -342,7 +342,8 @@ func (a *Account) DumpWIFPrivateKey(addr btcutil.Address) (string, error) {
|
|||
}
|
||||
|
||||
// Return WIF-encoding of the private key.
|
||||
return btcutil.EncodePrivateKey(key.D.Bytes(), a.Net(), info.Compressed)
|
||||
return btcutil.EncodePrivateKey(key.D.Bytes(), a.Net(),
|
||||
info.Compressed())
|
||||
}
|
||||
|
||||
// ImportPrivateKey imports a private key to the account's wallet and
|
||||
|
@ -497,7 +498,7 @@ func (a *Account) SortedActivePaymentAddresses() []string {
|
|||
|
||||
addrs := make([]string, len(infos))
|
||||
for i, info := range infos {
|
||||
addrs[i] = info.Address.EncodeAddress()
|
||||
addrs[i] = info.Address().EncodeAddress()
|
||||
}
|
||||
|
||||
return addrs
|
||||
|
@ -510,7 +511,7 @@ func (a *Account) ActivePaymentAddresses() map[string]struct{} {
|
|||
|
||||
addrs := make(map[string]struct{}, len(infos))
|
||||
for _, info := range infos {
|
||||
addrs[info.Address.EncodeAddress()] = struct{}{}
|
||||
addrs[info.Address().EncodeAddress()] = struct{}{}
|
||||
}
|
||||
|
||||
return addrs
|
||||
|
@ -595,7 +596,7 @@ func (a *Account) RecoverAddresses(n int) error {
|
|||
m[addrs[i].EncodeAddress()] = struct{}{}
|
||||
}
|
||||
go func(addrs map[string]struct{}) {
|
||||
jsonErr := Rescan(CurrentServerConn(), lastInfo.FirstBlock, addrs)
|
||||
jsonErr := Rescan(CurrentServerConn(), lastInfo.FirstBlock(), addrs)
|
||||
if jsonErr != nil {
|
||||
log.Errorf("Rescanning for recovered addresses failed: %v",
|
||||
jsonErr.Message)
|
||||
|
|
|
@ -257,7 +257,7 @@ func (a *Account) txToPairs(pairs map[string]int64, minconf int) (*CreatedTx, er
|
|||
|
||||
sigscript, err := btcscript.SignatureScript(msgtx, i,
|
||||
input.PkScript(), btcscript.SigHashAll, privkey,
|
||||
ai.Compressed)
|
||||
ai.Compressed())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create sigscript: %s", err)
|
||||
}
|
||||
|
|
13
rpcserver.go
13
rpcserver.go
|
@ -1493,7 +1493,7 @@ func SignMessage(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
|
|||
|
||||
fullmsg := "Bitcoin Signed Message:\n" + cmd.Message
|
||||
sigbytes, err := btcec.SignCompact(btcec.S256(), privkey,
|
||||
btcwire.DoubleSha256([]byte(fullmsg)), ainfo.Compressed)
|
||||
btcwire.DoubleSha256([]byte(fullmsg)), ainfo.Compressed())
|
||||
if err != nil {
|
||||
return nil, &btcjson.Error{
|
||||
Code: btcjson.ErrWallet.Code,
|
||||
|
@ -1600,13 +1600,18 @@ func ValidateAddress(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
|
|||
result["ismine"] = true
|
||||
result["account"] = account
|
||||
|
||||
switch info := ainfo.(type) {
|
||||
case *wallet.AddressPubKeyInfo:
|
||||
result["compressed"] = info.Compressed()
|
||||
result["pubkey"] = info.Pubkey
|
||||
default:
|
||||
}
|
||||
|
||||
// TODO(oga) when we handle different types of addresses then
|
||||
// we will need to check here and only provide the script,
|
||||
// hexsript and list of addresses.
|
||||
// if scripthash, the pubkey if pubkey/pubkeyhash, etc.
|
||||
// for now we only support p2pkh so is irrelavent
|
||||
result["compressed"] = ainfo.Compressed
|
||||
result["pubkey"] = ainfo.Pubkey
|
||||
} else {
|
||||
result["ismine"] = false
|
||||
}
|
||||
|
@ -1681,7 +1686,7 @@ func VerifyMessage(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
|
|||
|
||||
// Return boolean if keys match.
|
||||
return (pk.X.Cmp(privkey.X) == 0 && pk.Y.Cmp(privkey.Y) == 0 &&
|
||||
ainfo.Compressed == wasCompressed), nil
|
||||
ainfo.Compressed() == wasCompressed), nil
|
||||
}
|
||||
|
||||
// WalletIsLocked handles the walletislocked extension request by
|
||||
|
|
101
wallet/wallet.go
101
wallet/wallet.go
|
@ -1165,7 +1165,7 @@ func (w *Wallet) AddressKey(a btcutil.Address) (key *ecdsa.PrivateKey, err error
|
|||
}
|
||||
|
||||
// AddressInfo returns an AddressInfo structure for an address in a wallet.
|
||||
func (w *Wallet) AddressInfo(a btcutil.Address) (*AddressInfo, error) {
|
||||
func (w *Wallet) AddressInfo(a btcutil.Address) (AddressInfo, error) {
|
||||
// Currently, only P2PKH addresses are supported. This should
|
||||
// be extended to a switch-case statement when support for other
|
||||
// addresses are added.
|
||||
|
@ -1404,24 +1404,77 @@ func (w *Wallet) ExportWatchingWallet() (*Wallet, error) {
|
|||
return ww, nil
|
||||
}
|
||||
|
||||
// AddressInfo holds information regarding an address needed to manage
|
||||
// a complete wallet.
|
||||
type AddressInfo struct {
|
||||
btcutil.Address
|
||||
AddrHash string
|
||||
Compressed bool
|
||||
FirstBlock int32
|
||||
Imported bool
|
||||
// AddressInfo is an interface that provides acces to information regarding an
|
||||
// address managed by a wallet. Concrete implementations of this type may
|
||||
// provide further fields to provide information specific to that type of
|
||||
// address.
|
||||
type AddressInfo interface {
|
||||
// Address returns a btcutil.Address for the backing address.
|
||||
Address() btcutil.Address
|
||||
// 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
|
||||
}
|
||||
|
||||
// AddressPubKeyInfo implements AddressInfo and additionally provides the
|
||||
// pubkey for a pubkey-based address.
|
||||
type AddressPubKeyInfo struct {
|
||||
address btcutil.Address
|
||||
addrHash string
|
||||
compressed bool
|
||||
firstBlock int32
|
||||
imported bool
|
||||
Pubkey string
|
||||
Change bool
|
||||
change bool
|
||||
}
|
||||
|
||||
// Address returns the pub key address, implementing AddressInfo.
|
||||
func (ai *AddressPubKeyInfo) Address() btcutil.Address {
|
||||
return ai.address
|
||||
}
|
||||
|
||||
// AddrHash returns the pub key hash, implementing AddressInfo.
|
||||
func (ai *AddressPubKeyInfo) AddrHash() string {
|
||||
return ai.addrHash
|
||||
}
|
||||
|
||||
// FirstBlock returns the first block the address is seen in, implementing
|
||||
// AddressInfo.
|
||||
func (ai *AddressPubKeyInfo) FirstBlock() int32 {
|
||||
return ai.firstBlock
|
||||
}
|
||||
|
||||
// Imported returns the pub if the address was imported, or a chained address,
|
||||
// implementing AddressInfo.
|
||||
func (ai *AddressPubKeyInfo) Imported() bool {
|
||||
return ai.imported
|
||||
}
|
||||
|
||||
// AddrHash returns true if the address was created as a change address,
|
||||
// implementing AddressInfo.
|
||||
func (ai *AddressPubKeyInfo) Change() bool {
|
||||
return ai.change
|
||||
}
|
||||
|
||||
// AddrHash returns true if the address backing key is compressed,
|
||||
// implementing AddressInfo.
|
||||
func (ai *AddressPubKeyInfo) Compressed() bool {
|
||||
return ai.compressed
|
||||
}
|
||||
|
||||
// SortedActiveAddresses returns all wallet addresses that have been
|
||||
// requested to be generated. These do not include unused addresses in
|
||||
// the key pool. Use this when ordered addresses are needed. Otherwise,
|
||||
// ActiveAddresses is preferred.
|
||||
func (w *Wallet) SortedActiveAddresses() []*AddressInfo {
|
||||
addrs := make([]*AddressInfo, 0,
|
||||
func (w *Wallet) SortedActiveAddresses() []AddressInfo {
|
||||
addrs := make([]AddressInfo, 0,
|
||||
w.highestUsed+int64(len(w.importedAddrs))+1)
|
||||
for i := int64(rootKeyChainIdx); i <= w.highestUsed; i++ {
|
||||
a := w.chainIdxMap[i]
|
||||
|
@ -1442,19 +1495,19 @@ func (w *Wallet) SortedActiveAddresses() []*AddressInfo {
|
|||
// ActiveAddresses returns a map between active payment addresses
|
||||
// and their full info. These do not include unused addresses in the
|
||||
// key pool. If addresses must be sorted, use SortedActiveAddresses.
|
||||
func (w *Wallet) ActiveAddresses() map[btcutil.Address]*AddressInfo {
|
||||
addrs := make(map[btcutil.Address]*AddressInfo)
|
||||
func (w *Wallet) ActiveAddresses() map[btcutil.Address]AddressInfo {
|
||||
addrs := make(map[btcutil.Address]AddressInfo)
|
||||
for i := int64(rootKeyChainIdx); i <= w.highestUsed; i++ {
|
||||
a := w.chainIdxMap[i]
|
||||
info, err := w.addrMap[*a].info(w.Net())
|
||||
if err == nil {
|
||||
addrs[info.Address] = info
|
||||
addrs[info.Address()] = info
|
||||
}
|
||||
}
|
||||
for _, addr := range w.importedAddrs {
|
||||
info, err := addr.info(w.Net())
|
||||
if err == nil {
|
||||
addrs[info.Address] = info
|
||||
addrs[info.Address()] = info
|
||||
}
|
||||
}
|
||||
return addrs
|
||||
|
@ -2273,17 +2326,17 @@ func (a *btcAddress) address(net btcwire.BitcoinNet) *btcutil.AddressPubKeyHash
|
|||
|
||||
// info returns information about a btcAddress stored in a AddressInfo
|
||||
// struct.
|
||||
func (a *btcAddress) info(net btcwire.BitcoinNet) (*AddressInfo, error) {
|
||||
func (a *btcAddress) info(net btcwire.BitcoinNet) (AddressInfo, error) {
|
||||
address := a.address(net)
|
||||
|
||||
return &AddressInfo{
|
||||
Address: address,
|
||||
AddrHash: string(a.pubKeyHash[:]),
|
||||
Compressed: a.flags.compressed,
|
||||
FirstBlock: a.firstBlock,
|
||||
Imported: a.chainIndex == importedKeyChainIdx,
|
||||
return &AddressPubKeyInfo{
|
||||
address: address,
|
||||
addrHash: string(a.pubKeyHash[:]),
|
||||
compressed: a.flags.compressed,
|
||||
firstBlock: a.firstBlock,
|
||||
imported: a.chainIndex == importedKeyChainIdx,
|
||||
Pubkey: hex.EncodeToString(a.pubKey),
|
||||
Change: a.flags.change,
|
||||
change: a.flags.change,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -347,12 +347,14 @@ func TestWalletPubkeyChaining(t *testing.T) {
|
|||
t.Errorf("Failed to get info about address without private key: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
pkinfo := info.(*AddressPubKeyInfo)
|
||||
// sanity checks
|
||||
if !info.Compressed {
|
||||
if !info.Compressed() {
|
||||
t.Errorf("Pubkey should be compressed.")
|
||||
return
|
||||
}
|
||||
if info.Imported {
|
||||
if info.Imported() {
|
||||
t.Errorf("Should not be marked as imported.")
|
||||
return
|
||||
}
|
||||
|
@ -419,7 +421,7 @@ func TestWalletPubkeyChaining(t *testing.T) {
|
|||
t.Errorf("Unable to sign hash with the created private key: %v", err)
|
||||
return
|
||||
}
|
||||
pubKeyStr, _ := hex.DecodeString(info.Pubkey)
|
||||
pubKeyStr, _ := hex.DecodeString(pkinfo.Pubkey)
|
||||
pubKey, err := btcec.ParsePubKey(pubKeyStr, btcec.S256())
|
||||
ok := ecdsa.Verify(pubKey, hash, r, s)
|
||||
if !ok {
|
||||
|
@ -442,6 +444,7 @@ func TestWalletPubkeyChaining(t *testing.T) {
|
|||
t.Errorf("Couldn't get info about the next address in the chain: %v", err)
|
||||
return
|
||||
}
|
||||
nextPkInfo := nextInfo.(*AddressPubKeyInfo)
|
||||
nextKey, err := w.AddressKey(nextAddr)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't get private key for the next address in the chain: %v", err)
|
||||
|
@ -455,7 +458,7 @@ func TestWalletPubkeyChaining(t *testing.T) {
|
|||
t.Errorf("Unable to sign hash with the created private key: %v", err)
|
||||
return
|
||||
}
|
||||
pubKeyStr, _ = hex.DecodeString(nextInfo.Pubkey)
|
||||
pubKeyStr, _ = hex.DecodeString(nextPkInfo.Pubkey)
|
||||
pubKey, err = btcec.ParsePubKey(pubKeyStr, btcec.S256())
|
||||
ok = ecdsa.Verify(pubKey, hash, r, s)
|
||||
if !ok {
|
||||
|
|
Loading…
Reference in a new issue