Switch to new btcutil Address encoding/decoding API.
This commit is contained in:
parent
ac79a59c90
commit
e8265eca41
8 changed files with 223 additions and 254 deletions
77
account.go
77
account.go
|
@ -134,7 +134,7 @@ func (a *Account) Rollback(height int32, hash *btcwire.ShaHash) {
|
|||
// a given address. Assumming correct TxStore usage, this will return true iff
|
||||
// there are any transactions with outputs to this address in the blockchain or
|
||||
// the btcd mempool.
|
||||
func (a *Account) AddressUsed(pkHash []byte) bool {
|
||||
func (a *Account) AddressUsed(addr btcutil.Address) bool {
|
||||
// This can be optimized by recording this data as it is read when
|
||||
// opening an account, and keeping it up to date each time a new
|
||||
// received tx arrives.
|
||||
|
@ -142,6 +142,8 @@ func (a *Account) AddressUsed(pkHash []byte) bool {
|
|||
a.TxStore.RLock()
|
||||
defer a.TxStore.RUnlock()
|
||||
|
||||
pkHash := addr.ScriptAddress()
|
||||
|
||||
for i := range a.TxStore.s {
|
||||
rtx, ok := a.TxStore.s[i].(*tx.RecvTx)
|
||||
if !ok {
|
||||
|
@ -193,7 +195,7 @@ func (a *Account) CalculateBalance(confirms int) float64 {
|
|||
// a UTXO must be in a block. If confirmations is 1 or greater,
|
||||
// the balance will be calculated based on how many how many blocks
|
||||
// include a UTXO.
|
||||
func (a *Account) CalculateAddressBalance(pubkeyHash []byte, confirms int) float64 {
|
||||
func (a *Account) CalculateAddressBalance(addr *btcutil.AddressPubKeyHash, confirms int) float64 {
|
||||
var bal uint64 // Measured in satoshi
|
||||
|
||||
bs, err := GetCurBlock()
|
||||
|
@ -206,7 +208,7 @@ func (a *Account) CalculateAddressBalance(pubkeyHash []byte, confirms int) float
|
|||
// Utxos not yet in blocks (height -1) should only be
|
||||
// added if confirmations is 0.
|
||||
if confirms == 0 || (u.Height != -1 && int(bs.Height-u.Height+1) >= confirms) {
|
||||
if bytes.Equal(pubkeyHash, u.AddrHash[:]) {
|
||||
if bytes.Equal(addr.ScriptAddress(), u.AddrHash[:]) {
|
||||
bal += u.Amt
|
||||
}
|
||||
}
|
||||
|
@ -219,22 +221,17 @@ func (a *Account) CalculateAddressBalance(pubkeyHash []byte, confirms int) float
|
|||
// from an account. If the address has already been used (there is at least
|
||||
// one transaction spending to it in the blockchain or btcd mempool), the next
|
||||
// chained address is returned.
|
||||
func (a *Account) CurrentAddress() (string, error) {
|
||||
func (a *Account) CurrentAddress() (btcutil.Address, error) {
|
||||
a.mtx.RLock()
|
||||
addr, err := a.Wallet.LastChainedAddress()
|
||||
addr := a.Wallet.LastChainedAddress()
|
||||
a.mtx.RUnlock()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Get next chained address if the last one has already been used.
|
||||
pkHash, _, _ := btcutil.DecodeAddress(addr)
|
||||
if a.AddressUsed(pkHash) {
|
||||
addr, err = a.NewAddress()
|
||||
if a.AddressUsed(addr) {
|
||||
return a.NewAddress()
|
||||
}
|
||||
|
||||
return addr, err
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// ListTransactions returns a slice of maps with details about a recorded
|
||||
|
@ -337,8 +334,8 @@ func (a *Account) ListAllTransactions() ([]map[string]interface{}, error) {
|
|||
return txInfoList, nil
|
||||
}
|
||||
|
||||
// DumpPrivKeys returns the WIF-encoded private keys for all addresses
|
||||
// non-watching addresses in a wallets.
|
||||
// DumpPrivKeys returns the WIF-encoded private keys for all addresses with
|
||||
// private keys in a wallet.
|
||||
func (a *Account) DumpPrivKeys() ([]string, error) {
|
||||
a.mtx.RLock()
|
||||
defer a.mtx.RUnlock()
|
||||
|
@ -346,13 +343,13 @@ func (a *Account) DumpPrivKeys() ([]string, error) {
|
|||
// Iterate over each active address, appending the private
|
||||
// key to privkeys.
|
||||
var privkeys []string
|
||||
for _, addr := range a.ActiveAddresses() {
|
||||
key, err := a.AddressKey(addr.Address)
|
||||
for addr, info := range a.ActiveAddresses() {
|
||||
key, err := a.AddressKey(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encKey, err := btcutil.EncodePrivateKey(key.D.Bytes(),
|
||||
a.Net(), addr.Compressed)
|
||||
a.Net(), info.Compressed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -364,19 +361,19 @@ func (a *Account) DumpPrivKeys() ([]string, error) {
|
|||
|
||||
// DumpWIFPrivateKey returns the WIF encoded private key for a
|
||||
// single wallet address.
|
||||
func (a *Account) DumpWIFPrivateKey(address string) (string, error) {
|
||||
func (a *Account) DumpWIFPrivateKey(addr btcutil.Address) (string, error) {
|
||||
a.mtx.RLock()
|
||||
defer a.mtx.RUnlock()
|
||||
|
||||
// Get private key from wallet if it exists.
|
||||
key, err := a.AddressKey(address)
|
||||
key, err := a.AddressKey(addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Get address info. This is needed to determine whether
|
||||
// the pubkey is compressed or not.
|
||||
info, err := a.AddressInfo(address)
|
||||
info, err := a.AddressInfo(addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -573,8 +570,8 @@ func (a *Account) SortedActivePaymentAddresses() []string {
|
|||
infos := a.SortedActiveAddresses()
|
||||
addrs := make([]string, len(infos))
|
||||
|
||||
for i, addr := range infos {
|
||||
addrs[i] = addr.Address
|
||||
for i, info := range infos {
|
||||
addrs[i] = info.Address.EncodeAddress()
|
||||
}
|
||||
|
||||
return addrs
|
||||
|
@ -590,29 +587,31 @@ func (a *Account) ActivePaymentAddresses() map[string]struct{} {
|
|||
addrs := make(map[string]struct{}, len(infos))
|
||||
|
||||
for _, info := range infos {
|
||||
addrs[info.Address] = struct{}{}
|
||||
addrs[info.Address.EncodeAddress()] = struct{}{}
|
||||
}
|
||||
|
||||
return addrs
|
||||
}
|
||||
|
||||
// NewAddress returns a new payment address for an account.
|
||||
func (a *Account) NewAddress() (string, error) {
|
||||
func (a *Account) NewAddress() (btcutil.Address, error) {
|
||||
a.mtx.Lock()
|
||||
|
||||
// Get current block's height and hash.
|
||||
bs, err := GetCurBlock()
|
||||
if err != nil {
|
||||
return "", err
|
||||
a.mtx.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get next address from wallet.
|
||||
addr, err := a.NextChainedAddress(&bs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
a.mtx.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Write updated wallet to disk.
|
||||
// Immediately write updated wallet to disk.
|
||||
a.dirty = true
|
||||
a.mtx.Unlock()
|
||||
if err = a.writeDirtyToDisk(); err != nil {
|
||||
|
@ -620,7 +619,7 @@ func (a *Account) NewAddress() (string, error) {
|
|||
}
|
||||
|
||||
// Mark this new address as belonging to this account.
|
||||
MarkAddressForAccount(addr, a.Name())
|
||||
MarkAddressForAccount(addr.EncodeAddress(), a.Name())
|
||||
|
||||
// Request updates from btcd for new transactions sent to this address.
|
||||
a.ReqNewTxsForAddress(addr)
|
||||
|
@ -630,15 +629,21 @@ func (a *Account) NewAddress() (string, error) {
|
|||
|
||||
// ReqNewTxsForAddress sends a message to btcd to request tx updates
|
||||
// for addr for each new block that is added to the blockchain.
|
||||
func (a *Account) ReqNewTxsForAddress(addr string) {
|
||||
log.Debugf("Requesting notifications of TXs sending to address %v", addr)
|
||||
func (a *Account) ReqNewTxsForAddress(addr btcutil.Address) {
|
||||
// Only support P2PKH addresses currently.
|
||||
apkh, ok := addr.(*btcutil.AddressPubKeyHash)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("Requesting notifications of TXs sending to address %v", apkh)
|
||||
|
||||
a.mtx.RLock()
|
||||
n := a.NewBlockTxJSONID
|
||||
a.mtx.RUnlock()
|
||||
|
||||
cmd := btcws.NewNotifyNewTXsCmd(fmt.Sprintf("btcwallet(%d)", n),
|
||||
[]string{addr})
|
||||
[]string{apkh.EncodeAddress()})
|
||||
mcmd, err := cmd.MarshalJSON()
|
||||
if err != nil {
|
||||
log.Errorf("cannot request transaction notifications: %v", err)
|
||||
|
@ -719,12 +724,12 @@ func (a *Account) newBlockTxOutHandler(result interface{}, e *btcjson.Error) boo
|
|||
}
|
||||
return false
|
||||
}
|
||||
receiver, ok := v["receiver"].(string)
|
||||
receiverStr, ok := v["receiver"].(string)
|
||||
if !ok {
|
||||
log.Error("Tx Handler: Unspecified receiver.")
|
||||
return false
|
||||
}
|
||||
receiverHash, _, err := btcutil.DecodeAddress(receiver)
|
||||
receiver, err := btcutil.DecodeAddr(receiverStr)
|
||||
if err != nil {
|
||||
log.Errorf("Tx Handler: receiver address can not be decoded: %v", err)
|
||||
return false
|
||||
|
@ -810,7 +815,7 @@ func (a *Account) newBlockTxOutHandler(result interface{}, e *btcjson.Error) boo
|
|||
BlockIndex: blockIndex,
|
||||
BlockTime: blockTime,
|
||||
Amount: int64(amt),
|
||||
ReceiverHash: receiverHash,
|
||||
ReceiverHash: receiver.ScriptAddress(),
|
||||
}
|
||||
|
||||
// For transactions originating from this wallet, the sent tx history should
|
||||
|
@ -863,7 +868,7 @@ func (a *Account) newBlockTxOutHandler(result interface{}, e *btcjson.Error) boo
|
|||
}
|
||||
copy(u.Out.Hash[:], txID[:])
|
||||
u.Out.Index = uint32(txOutIndex)
|
||||
copy(u.AddrHash[:], receiverHash)
|
||||
copy(u.AddrHash[:], receiver.ScriptAddress())
|
||||
copy(u.BlockHash[:], blockHash[:])
|
||||
a.UtxoStore.Lock()
|
||||
a.UtxoStore.s.Insert(u)
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/conformal/btcutil"
|
||||
"github.com/conformal/btcwallet/tx"
|
||||
"github.com/conformal/btcwallet/wallet"
|
||||
"github.com/conformal/btcwire"
|
||||
|
@ -247,7 +248,7 @@ func (store *AccountStore) DumpKeys() ([]string, error) {
|
|||
|
||||
// DumpWIFPrivateKey searches through all accounts for the bitcoin
|
||||
// payment address addr and returns the WIF-encdoded private key.
|
||||
func (store *AccountStore) DumpWIFPrivateKey(addr string) (string, error) {
|
||||
func (store *AccountStore) DumpWIFPrivateKey(addr btcutil.Address) (string, error) {
|
||||
store.Lock()
|
||||
defer store.Unlock()
|
||||
|
||||
|
|
64
cmdmgr.go
64
cmdmgr.go
|
@ -233,7 +233,13 @@ func DumpPrivKey(frontend chan []byte, icmd btcjson.Cmd) {
|
|||
return
|
||||
}
|
||||
|
||||
switch key, err := accountstore.DumpWIFPrivateKey(cmd.Address); err {
|
||||
addr, err := btcutil.DecodeAddr(cmd.Address)
|
||||
if err != nil {
|
||||
ReplyError(frontend, cmd.Id(), &btcjson.ErrInvalidAddressOrKey)
|
||||
return
|
||||
}
|
||||
|
||||
switch key, err := accountstore.DumpWIFPrivateKey(addr); err {
|
||||
case nil:
|
||||
// Key was found.
|
||||
ReplySuccess(frontend, cmd.Id(), key)
|
||||
|
@ -349,8 +355,24 @@ func GetAccount(frontend chan []byte, icmd btcjson.Cmd) {
|
|||
}
|
||||
|
||||
// Is address valid?
|
||||
_, net, err := btcutil.DecodeAddress(cmd.Address)
|
||||
if err != nil || net != cfg.Net() {
|
||||
addr, err := btcutil.DecodeAddr(cmd.Address)
|
||||
if err != nil {
|
||||
ReplyError(frontend, cmd.Id(), &btcjson.ErrInvalidAddressOrKey)
|
||||
return
|
||||
}
|
||||
var net btcwire.BitcoinNet
|
||||
switch a := addr.(type) {
|
||||
case *btcutil.AddressPubKeyHash:
|
||||
net = a.Net()
|
||||
|
||||
case *btcutil.AddressScriptHash:
|
||||
net = a.Net()
|
||||
|
||||
default:
|
||||
ReplyError(frontend, cmd.Id(), &btcjson.ErrInvalidAddressOrKey)
|
||||
return
|
||||
}
|
||||
if net != cfg.Net() {
|
||||
ReplyError(frontend, cmd.Id(), &btcjson.ErrInvalidAddressOrKey)
|
||||
return
|
||||
}
|
||||
|
@ -429,8 +451,13 @@ func GetAddressBalance(frontend chan []byte, icmd btcjson.Cmd) {
|
|||
}
|
||||
|
||||
// Is address valid?
|
||||
pkhash, net, err := btcutil.DecodeAddress(cmd.Address)
|
||||
if err != nil || net != cfg.Net() {
|
||||
addr, err := btcutil.DecodeAddr(cmd.Address)
|
||||
if err != nil {
|
||||
ReplyError(frontend, cmd.Id(), &btcjson.ErrInvalidAddressOrKey)
|
||||
return
|
||||
}
|
||||
apkh, ok := addr.(*btcutil.AddressPubKeyHash)
|
||||
if !ok || apkh.Net() != cfg.Net() {
|
||||
ReplyError(frontend, cmd.Id(), &btcjson.ErrInvalidAddressOrKey)
|
||||
return
|
||||
}
|
||||
|
@ -455,7 +482,7 @@ func GetAddressBalance(frontend chan []byte, icmd btcjson.Cmd) {
|
|||
return
|
||||
}
|
||||
|
||||
bal := a.CalculateAddressBalance(pkhash, int(cmd.Minconf))
|
||||
bal := a.CalculateAddressBalance(apkh, int(cmd.Minconf))
|
||||
ReplySuccess(frontend, cmd.Id(), bal)
|
||||
}
|
||||
|
||||
|
@ -712,19 +739,20 @@ func ListAddressTransactions(frontend chan []byte, icmd btcjson.Cmd) {
|
|||
return
|
||||
}
|
||||
|
||||
// Parse hash160s out of addresses.
|
||||
// Decode addresses.
|
||||
pkHashMap := make(map[string]struct{})
|
||||
for _, addr := range cmd.Addresses {
|
||||
pkHash, net, err := btcutil.DecodeAddress(addr)
|
||||
if err != nil || net != cfg.Net() {
|
||||
e := &btcjson.Error{
|
||||
Code: btcjson.ErrInvalidParams.Code,
|
||||
Message: "invalid address",
|
||||
}
|
||||
ReplyError(frontend, cmd.Id(), e)
|
||||
for _, addrStr := range cmd.Addresses {
|
||||
addr, err := btcutil.DecodeAddr(addrStr)
|
||||
if err != nil {
|
||||
ReplyError(frontend, cmd.Id(), &btcjson.ErrInvalidAddressOrKey)
|
||||
return
|
||||
}
|
||||
pkHashMap[string(pkHash)] = struct{}{}
|
||||
apkh, ok := addr.(*btcutil.AddressPubKeyHash)
|
||||
if !ok || apkh.Net() != cfg.Net() {
|
||||
ReplyError(frontend, cmd.Id(), &btcjson.ErrInvalidAddressOrKey)
|
||||
return
|
||||
}
|
||||
pkHashMap[string(addr.ScriptAddress())] = struct{}{}
|
||||
}
|
||||
|
||||
txList, err := a.ListAddressTransactions(pkHashMap)
|
||||
|
@ -863,7 +891,7 @@ func SendFrom(frontend chan []byte, icmd btcjson.Cmd) {
|
|||
|
||||
// If a change address was added, mark wallet as dirty, sync to disk,
|
||||
// and request updates for change address.
|
||||
if len(createdTx.changeAddr) != 0 {
|
||||
if createdTx.changeAddr != nil {
|
||||
a.dirty = true
|
||||
if err := a.writeDirtyToDisk(); err != nil {
|
||||
log.Errorf("cannot write dirty wallet: %v", err)
|
||||
|
@ -955,7 +983,7 @@ func SendMany(frontend chan []byte, icmd btcjson.Cmd) {
|
|||
|
||||
// If a change address was added, mark wallet as dirty, sync to disk,
|
||||
// and request updates for change address.
|
||||
if len(createdTx.changeAddr) != 0 {
|
||||
if createdTx.changeAddr != nil {
|
||||
a.dirty = true
|
||||
if err := a.writeDirtyToDisk(); err != nil {
|
||||
log.Errorf("cannot write dirty wallet: %v", err)
|
||||
|
|
41
createtx.go
41
createtx.go
|
@ -71,7 +71,7 @@ type CreatedTx struct {
|
|||
outputs []tx.Pair
|
||||
btcspent int64
|
||||
fee int64
|
||||
changeAddr string
|
||||
changeAddr *btcutil.AddressPubKeyHash
|
||||
changeUtxo *tx.Utxo
|
||||
}
|
||||
|
||||
|
@ -181,14 +181,14 @@ func (a *Account) txToPairs(pairs map[string]int64, minconf int) (*CreatedTx, er
|
|||
outputs := make([]tx.Pair, 0, len(pairs)+1)
|
||||
|
||||
// Add outputs to new tx.
|
||||
for addr, amt := range pairs {
|
||||
addr160, _, err := btcutil.DecodeAddress(addr)
|
||||
for addrStr, amt := range pairs {
|
||||
addr, err := btcutil.DecodeAddr(addrStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot decode address: %s", err)
|
||||
}
|
||||
|
||||
// Spend amt to addr160
|
||||
pkScript, err := btcscript.PayToPubKeyHashScript(addr160)
|
||||
// Add output to spend amt to addr.
|
||||
pkScript, err := btcscript.PayToAddrScript(addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create txout script: %s", err)
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ func (a *Account) txToPairs(pairs map[string]int64, minconf int) (*CreatedTx, er
|
|||
// Create amount, address pair and add to outputs.
|
||||
out := tx.Pair{
|
||||
Amount: amt,
|
||||
PubkeyHash: addr160,
|
||||
PubkeyHash: addr.ScriptAddress(),
|
||||
}
|
||||
outputs = append(outputs, out)
|
||||
}
|
||||
|
@ -216,8 +216,7 @@ func (a *Account) txToPairs(pairs map[string]int64, minconf int) (*CreatedTx, er
|
|||
|
||||
// These are nil/zeroed until a change address is needed, and reused
|
||||
// again in case a change utxo has already been chosen.
|
||||
var changeAddrHash []byte
|
||||
var changeAddr string
|
||||
var changeAddr *btcutil.AddressPubKeyHash
|
||||
|
||||
var btcspent int64
|
||||
var selectedInputs []*tx.Utxo
|
||||
|
@ -245,23 +244,18 @@ func (a *Account) txToPairs(pairs map[string]int64, minconf int) (*CreatedTx, er
|
|||
// Create a new address to spend leftover outputs to.
|
||||
|
||||
// Get a new change address if one has not already been found.
|
||||
if changeAddrHash == nil {
|
||||
if changeAddr == nil {
|
||||
changeAddr, err = a.NextChainedAddress(&bs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get next address: %s", err)
|
||||
}
|
||||
|
||||
// Mark change address as belonging to this account.
|
||||
MarkAddressForAccount(changeAddr, a.Name())
|
||||
|
||||
changeAddrHash, _, err = btcutil.DecodeAddress(changeAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot decode new address: %s", err)
|
||||
}
|
||||
MarkAddressForAccount(changeAddr.EncodeAddress(), a.Name())
|
||||
}
|
||||
|
||||
// Spend change.
|
||||
pkScript, err := btcscript.PayToPubKeyHashScript(changeAddrHash)
|
||||
pkScript, err := btcscript.PayToAddrScript(changeAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create txout script: %s", err)
|
||||
}
|
||||
|
@ -278,7 +272,7 @@ func (a *Account) txToPairs(pairs map[string]int64, minconf int) (*CreatedTx, er
|
|||
Height: -1,
|
||||
Subscript: pkScript,
|
||||
}
|
||||
copy(changeUtxo.AddrHash[:], changeAddrHash)
|
||||
copy(changeUtxo.AddrHash[:], changeAddr.ScriptAddress())
|
||||
}
|
||||
|
||||
// Selected unspent outputs become new transaction's inputs.
|
||||
|
@ -286,18 +280,17 @@ func (a *Account) txToPairs(pairs map[string]int64, minconf int) (*CreatedTx, er
|
|||
msgtx.AddTxIn(btcwire.NewTxIn((*btcwire.OutPoint)(&ip.Out), nil))
|
||||
}
|
||||
for i, ip := range inputs {
|
||||
addrstr, err := btcutil.EncodeAddress(ip.AddrHash[:],
|
||||
// Error is ignored as the length and network checks can never fail
|
||||
// for these inputs.
|
||||
addr, _ := btcutil.NewAddressPubKeyHash(ip.AddrHash[:],
|
||||
a.Wallet.Net())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
privkey, err := a.AddressKey(addrstr)
|
||||
privkey, err := a.AddressKey(addr)
|
||||
if err == wallet.ErrWalletLocked {
|
||||
return nil, wallet.ErrWalletLocked
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("cannot get address key: %v", err)
|
||||
}
|
||||
ai, err := a.AddressInfo(addrstr)
|
||||
ai, err := a.AddressInfo(addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get address info: %v", err)
|
||||
}
|
||||
|
@ -326,7 +319,7 @@ func (a *Account) txToPairs(pairs map[string]int64, minconf int) (*CreatedTx, er
|
|||
// Add change to outputs.
|
||||
out := tx.Pair{
|
||||
Amount: int64(change),
|
||||
PubkeyHash: changeAddrHash,
|
||||
PubkeyHash: changeAddr.ScriptAddress(),
|
||||
Change: true,
|
||||
}
|
||||
outputs = append(outputs, out)
|
||||
|
|
|
@ -89,18 +89,13 @@ func TestFakeTxs(t *testing.T) {
|
|||
t.Errorf("Cannot get next address: %s", err)
|
||||
return
|
||||
}
|
||||
addr160, _, err := btcutil.DecodeAddress(addr)
|
||||
if err != nil {
|
||||
t.Errorf("Cannot decode address: %s", err)
|
||||
return
|
||||
}
|
||||
copy(utxo.AddrHash[:], addr160)
|
||||
copy(utxo.AddrHash[:], addr.ScriptAddress())
|
||||
ophash := (btcwire.ShaHash)([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||
28, 29, 30, 31, 32})
|
||||
out := btcwire.NewOutPoint(&ophash, 0)
|
||||
utxo.Out = tx.OutPoint(*out)
|
||||
ss, err := btcscript.PayToPubKeyHashScript(addr160)
|
||||
ss, err := btcscript.PayToAddrScript(addr)
|
||||
if err != nil {
|
||||
t.Errorf("Could not create utxo PkScript: %s", err)
|
||||
return
|
||||
|
|
15
tx/tx.go
15
tx/tx.go
|
@ -1004,9 +1004,10 @@ func (tx *RecvTx) WriteTo(w io.Writer) (n int64, err error) {
|
|||
func (tx *RecvTx) TxInfo(account string, curheight int32,
|
||||
net btcwire.BitcoinNet) map[string]interface{} {
|
||||
|
||||
address, err := btcutil.EncodeAddress(tx.ReceiverHash, net)
|
||||
if err != nil {
|
||||
address = "Unknown"
|
||||
address := "Unknown"
|
||||
addr, err := btcutil.NewAddressPubKeyHash(tx.ReceiverHash, net)
|
||||
if err == nil {
|
||||
address = addr.String()
|
||||
}
|
||||
|
||||
txInfo := map[string]interface{}{
|
||||
|
@ -1137,10 +1138,10 @@ func (tx *SendTx) TxInfo(account string, curheight int32,
|
|||
blockHashStr := blockHash.String()
|
||||
|
||||
for i, pair := range tx.Receivers {
|
||||
// EncodeAddress cannot error with these inputs.
|
||||
address, err := btcutil.EncodeAddress(pair.PubkeyHash, net)
|
||||
if err != nil {
|
||||
address = "Unknown"
|
||||
address := "Unknown"
|
||||
addr, err := btcutil.NewAddressPubKeyHash(pair.PubkeyHash, net)
|
||||
if err == nil {
|
||||
address = addr.String()
|
||||
}
|
||||
info := map[string]interface{}{
|
||||
"account": account,
|
||||
|
|
267
wallet/wallet.go
267
wallet/wallet.go
|
@ -32,7 +32,7 @@ import (
|
|||
"github.com/conformal/btcec"
|
||||
"github.com/conformal/btcutil"
|
||||
"github.com/conformal/btcwire"
|
||||
"hash"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"io"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
@ -111,27 +111,6 @@ func binaryWrite(w io.Writer, order binary.ByteOrder, data interface{}) (n int64
|
|||
return int64(written), err
|
||||
}
|
||||
|
||||
// Calculate the hash of hasher over buf.
|
||||
func calcHash(buf []byte, hasher hash.Hash) []byte {
|
||||
hasher.Write(buf)
|
||||
return hasher.Sum(nil)
|
||||
}
|
||||
|
||||
// calculate hash160 which is ripemd160(sha256(data))
|
||||
func calcHash160(buf []byte) []byte {
|
||||
return calcHash(calcHash(buf, sha256.New()), ripemd160.New())
|
||||
}
|
||||
|
||||
// calculate hash256 which is sha256(sha256(data))
|
||||
func calcHash256(buf []byte) []byte {
|
||||
return calcHash(calcHash(buf, sha256.New()), sha256.New())
|
||||
}
|
||||
|
||||
// calculate sha512(data)
|
||||
func calcSha512(buf []byte) []byte {
|
||||
return calcHash(buf, sha512.New())
|
||||
}
|
||||
|
||||
// pubkeyFromPrivkey creates an encoded pubkey based on a
|
||||
// 32-byte privkey. The returned pubkey is 33 bytes if compressed,
|
||||
// or 65 bytes if uncompressed.
|
||||
|
@ -154,11 +133,11 @@ func keyOneIter(passphrase, salt []byte, memReqts uint64) []byte {
|
|||
lutbl := make([]byte, memReqts)
|
||||
|
||||
// Seed for lookup table
|
||||
seed := calcSha512(saltedpass)
|
||||
copy(lutbl[:sha512.Size], seed)
|
||||
seed := sha512.Sum512(saltedpass)
|
||||
copy(lutbl[:sha512.Size], seed[:])
|
||||
|
||||
for nByte := 0; nByte < (int(memReqts) - sha512.Size); nByte += sha512.Size {
|
||||
hash := calcSha512(lutbl[nByte : nByte+sha512.Size])
|
||||
hash := sha512.Sum512(lutbl[nByte : nByte+sha512.Size])
|
||||
copy(lutbl[nByte+sha512.Size:nByte+2*sha512.Size], hash[:])
|
||||
}
|
||||
|
||||
|
@ -180,7 +159,7 @@ func keyOneIter(passphrase, salt []byte, memReqts uint64) []byte {
|
|||
}
|
||||
|
||||
// Save new hash to x
|
||||
hash := calcSha512(x)
|
||||
hash := sha512.Sum512(x)
|
||||
copy(x, hash[:])
|
||||
}
|
||||
|
||||
|
@ -230,7 +209,7 @@ func ChainedPrivKey(privkey, pubkey, chaincode []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
xorbytes := make([]byte, 32)
|
||||
chainMod := calcHash256(pubkey)
|
||||
chainMod := sha256.Sum256(pubkey)
|
||||
for i := range xorbytes {
|
||||
xorbytes[i] = chainMod[i] ^ chaincode[i]
|
||||
}
|
||||
|
@ -450,7 +429,6 @@ func (v *varEntries) ReadFrom(r io.Reader) (n int64, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
type addressHashKey string
|
||||
type transactionHashKey string
|
||||
type comment []byte
|
||||
|
||||
|
@ -472,8 +450,8 @@ type Wallet struct {
|
|||
// root address and the appended entries.
|
||||
recent recentBlocks
|
||||
|
||||
addrMap map[addressHashKey]*btcAddress
|
||||
addrCommentMap map[addressHashKey]comment
|
||||
addrMap map[btcutil.AddressPubKeyHash]*btcAddress
|
||||
addrCommentMap map[btcutil.AddressPubKeyHash]comment
|
||||
txCommentMap map[transactionHashKey]comment
|
||||
|
||||
// These are not serialized.
|
||||
|
@ -481,7 +459,7 @@ type Wallet struct {
|
|||
sync.Mutex
|
||||
key []byte
|
||||
}
|
||||
chainIdxMap map[int64]addressHashKey
|
||||
chainIdxMap map[int64]*btcutil.AddressPubKeyHash
|
||||
importedAddrs []*btcAddress
|
||||
lastChainIdx int64
|
||||
}
|
||||
|
@ -490,9 +468,7 @@ type Wallet struct {
|
|||
// desc's binary representation must not exceed 32 and 256 bytes,
|
||||
// respectively. All address private keys are encrypted with passphrase.
|
||||
// The wallet is returned unlocked.
|
||||
func NewWallet(name, desc string, passphrase []byte, net btcwire.BitcoinNet,
|
||||
createdAt *BlockStamp) (*Wallet, error) {
|
||||
|
||||
func NewWallet(name, desc string, passphrase []byte, net btcwire.BitcoinNet, createdAt *BlockStamp) (*Wallet, error) {
|
||||
// Check sizes of inputs.
|
||||
if len([]byte(name)) > 32 {
|
||||
return nil, errors.New("name exceeds 32 byte maximum size")
|
||||
|
@ -501,6 +477,11 @@ func NewWallet(name, desc string, passphrase []byte, net btcwire.BitcoinNet,
|
|||
return nil, errors.New("desc exceeds 256 byte maximum size")
|
||||
}
|
||||
|
||||
// Check for a valid network.
|
||||
if !(net == btcwire.MainNet || net == btcwire.TestNet3) {
|
||||
return nil, errors.New("wallets must use mainnet or testnet3")
|
||||
}
|
||||
|
||||
// Randomly-generate rootkey and chaincode.
|
||||
rootkey, chaincode := make([]byte, 32), make([]byte, 32)
|
||||
if _, err := rand.Read(rootkey); err != nil {
|
||||
|
@ -550,18 +531,18 @@ func NewWallet(name, desc string, passphrase []byte, net btcwire.BitcoinNet,
|
|||
&createdAt.Hash,
|
||||
},
|
||||
},
|
||||
addrMap: make(map[addressHashKey]*btcAddress),
|
||||
addrCommentMap: make(map[addressHashKey]comment),
|
||||
addrMap: make(map[btcutil.AddressPubKeyHash]*btcAddress),
|
||||
addrCommentMap: make(map[btcutil.AddressPubKeyHash]comment),
|
||||
txCommentMap: make(map[transactionHashKey]comment),
|
||||
chainIdxMap: make(map[int64]addressHashKey),
|
||||
chainIdxMap: make(map[int64]*btcutil.AddressPubKeyHash),
|
||||
lastChainIdx: rootKeyChainIdx,
|
||||
}
|
||||
copy(w.name[:], []byte(name))
|
||||
copy(w.desc[:], []byte(desc))
|
||||
|
||||
// Add root address to maps.
|
||||
w.addrMap[addressHashKey(w.keyGenerator.pubKeyHash[:])] = &w.keyGenerator
|
||||
w.chainIdxMap[rootKeyChainIdx] = addressHashKey(w.keyGenerator.pubKeyHash[:])
|
||||
w.addrMap[*w.keyGenerator.address(net)] = &w.keyGenerator
|
||||
w.chainIdxMap[rootKeyChainIdx] = w.keyGenerator.address(net)
|
||||
|
||||
// Fill keypool.
|
||||
if err := w.extendKeypool(nKeypoolIncrement, aeskey, createdAt); err != nil {
|
||||
|
@ -589,9 +570,9 @@ func (w *Wallet) Name() string {
|
|||
func (w *Wallet) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
var read int64
|
||||
|
||||
w.addrMap = make(map[addressHashKey]*btcAddress)
|
||||
w.addrCommentMap = make(map[addressHashKey]comment)
|
||||
w.chainIdxMap = make(map[int64]addressHashKey)
|
||||
w.addrMap = make(map[btcutil.AddressPubKeyHash]*btcAddress)
|
||||
w.addrCommentMap = make(map[btcutil.AddressPubKeyHash]comment)
|
||||
w.chainIdxMap = make(map[int64]*btcutil.AddressPubKeyHash)
|
||||
w.txCommentMap = make(map[transactionHashKey]comment)
|
||||
|
||||
var id [8]byte
|
||||
|
@ -640,29 +621,29 @@ func (w *Wallet) ReadFrom(r io.Reader) (n int64, err error) {
|
|||
}
|
||||
|
||||
// Add root address to address map.
|
||||
rootAddrKey := addressHashKey(w.keyGenerator.pubKeyHash[:])
|
||||
w.addrMap[rootAddrKey] = &w.keyGenerator
|
||||
w.chainIdxMap[rootKeyChainIdx] = rootAddrKey
|
||||
rootAddr := w.keyGenerator.address(w.net)
|
||||
w.addrMap[*rootAddr] = &w.keyGenerator
|
||||
w.chainIdxMap[rootKeyChainIdx] = rootAddr
|
||||
|
||||
// Fill unserializied fields.
|
||||
wts := ([]io.WriterTo)(appendedEntries)
|
||||
for _, wt := range wts {
|
||||
switch e := wt.(type) {
|
||||
case *addrEntry:
|
||||
addrKey := addressHashKey(e.pubKeyHash160[:])
|
||||
w.addrMap[addrKey] = &e.addr
|
||||
addr := e.addr.address(w.net)
|
||||
w.addrMap[*addr] = &e.addr
|
||||
if e.addr.chainIndex == importedKeyChainIdx {
|
||||
w.importedAddrs = append(w.importedAddrs, &e.addr)
|
||||
} else {
|
||||
w.chainIdxMap[e.addr.chainIndex] = addrKey
|
||||
w.chainIdxMap[e.addr.chainIndex] = addr
|
||||
if w.lastChainIdx < e.addr.chainIndex {
|
||||
w.lastChainIdx = e.addr.chainIndex
|
||||
}
|
||||
}
|
||||
|
||||
case *addrCommentEntry:
|
||||
addrKey := addressHashKey(e.pubKeyHash160[:])
|
||||
w.addrCommentMap[addrKey] = comment(e.comment)
|
||||
addr := e.address(w.net)
|
||||
w.addrCommentMap[*addr] = comment(e.comment)
|
||||
|
||||
case *txCommentEntry:
|
||||
txKey := transactionHashKey(e.txHash[:])
|
||||
|
@ -682,26 +663,26 @@ func (w *Wallet) WriteTo(wtr io.Writer) (n int64, err error) {
|
|||
var wts []io.WriterTo
|
||||
var chainedAddrs = make([]io.WriterTo, len(w.chainIdxMap)-1)
|
||||
var importedAddrs []io.WriterTo
|
||||
for hash, addr := range w.addrMap {
|
||||
for addr, btcAddr := range w.addrMap {
|
||||
e := &addrEntry{
|
||||
addr: *addr,
|
||||
addr: *btcAddr,
|
||||
}
|
||||
copy(e.pubKeyHash160[:], []byte(hash))
|
||||
if addr.chainIndex >= 0 {
|
||||
copy(e.pubKeyHash160[:], addr.ScriptAddress())
|
||||
if btcAddr.chainIndex >= 0 {
|
||||
// Chained addresses are sorted. This is
|
||||
// kind of nice but probably isn't necessary.
|
||||
chainedAddrs[addr.chainIndex] = e
|
||||
} else if addr.chainIndex == importedKeyChainIdx {
|
||||
chainedAddrs[btcAddr.chainIndex] = e
|
||||
} else if btcAddr.chainIndex == importedKeyChainIdx {
|
||||
// No order for imported addresses.
|
||||
importedAddrs = append(importedAddrs, e)
|
||||
}
|
||||
}
|
||||
wts = append(chainedAddrs, importedAddrs...)
|
||||
for hash, comment := range w.addrCommentMap {
|
||||
for addr, comment := range w.addrCommentMap {
|
||||
e := &addrCommentEntry{
|
||||
comment: []byte(comment),
|
||||
}
|
||||
copy(e.pubKeyHash160[:], []byte(hash))
|
||||
copy(e.pubKeyHash160[:], addr.ScriptAddress())
|
||||
wts = append(wts, e)
|
||||
}
|
||||
for hash, comment := range w.txCommentMap {
|
||||
|
@ -814,7 +795,7 @@ func (w *Wallet) Version() (string, int) {
|
|||
|
||||
// NextChainedAddress attempts to get the next chained address,
|
||||
// refilling the keypool if necessary.
|
||||
func (w *Wallet) NextChainedAddress(bs *BlockStamp) (string, error) {
|
||||
func (w *Wallet) NextChainedAddress(bs *BlockStamp) (*btcutil.AddressPubKeyHash, error) {
|
||||
// Attempt to get address hash of next chained address.
|
||||
next160, ok := w.chainIdxMap[w.highestUsed+1]
|
||||
if !ok {
|
||||
|
@ -823,61 +804,50 @@ func (w *Wallet) NextChainedAddress(bs *BlockStamp) (string, error) {
|
|||
w.secret.Lock()
|
||||
if len(w.secret.key) != 32 {
|
||||
w.secret.Unlock()
|
||||
return "", ErrWalletLocked
|
||||
return nil, ErrWalletLocked
|
||||
}
|
||||
copy(aeskey, w.secret.key)
|
||||
w.secret.Unlock()
|
||||
|
||||
err := w.extendKeypool(nKeypoolIncrement, aeskey, bs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
next160, ok = w.chainIdxMap[w.highestUsed+1]
|
||||
if !ok {
|
||||
return "", errors.New("chain index map inproperly updated")
|
||||
return nil, errors.New("chain index map inproperly updated")
|
||||
}
|
||||
}
|
||||
|
||||
// Look up address.
|
||||
addr, ok := w.addrMap[next160]
|
||||
addr, ok := w.addrMap[*next160]
|
||||
if !ok {
|
||||
return "", errors.New("cannot find generated address")
|
||||
return nil, errors.New("cannot find generated address")
|
||||
}
|
||||
|
||||
w.highestUsed++
|
||||
|
||||
// Create and return payment address for address hash.
|
||||
return addr.paymentAddress(w.net)
|
||||
return addr.address(w.net), nil
|
||||
}
|
||||
|
||||
// LastChainedAddress returns the most recently requested chained
|
||||
// address from calling NextChainedAddress, or the root address if
|
||||
// no chained addresses have been requested.
|
||||
func (w *Wallet) LastChainedAddress() (string, error) {
|
||||
// Lookup pubkey hash for last used chained address.
|
||||
pkHash, ok := w.chainIdxMap[w.highestUsed]
|
||||
if !ok {
|
||||
return "", errors.New("chain index references unknown address")
|
||||
}
|
||||
|
||||
// Lookup address with this pubkey hash.
|
||||
addr, ok := w.addrMap[pkHash]
|
||||
if !ok {
|
||||
return "", errors.New("cannot find address by pubkey hash")
|
||||
}
|
||||
|
||||
// Create and return payment address from serialized pubkey.
|
||||
return addr.paymentAddress(w.net)
|
||||
func (w *Wallet) LastChainedAddress() btcutil.Address {
|
||||
return w.chainIdxMap[w.highestUsed]
|
||||
}
|
||||
|
||||
// extendKeypool grows the keypool by n addresses.
|
||||
func (w *Wallet) extendKeypool(n uint, aeskey []byte, bs *BlockStamp) error {
|
||||
// Get last chained address. New chained addresses will be
|
||||
// chained off of this address's chaincode and private key.
|
||||
addrKey := w.chainIdxMap[w.lastChainIdx]
|
||||
addr, ok := w.addrMap[addrKey]
|
||||
a := w.chainIdxMap[w.lastChainIdx]
|
||||
addr, ok := w.addrMap[*a]
|
||||
if !ok {
|
||||
spew.Dump(a)
|
||||
spew.Dump(w.addrMap)
|
||||
return errors.New("expected last chained address not found")
|
||||
}
|
||||
privkey, err := addr.unlock(aeskey)
|
||||
|
@ -903,10 +873,10 @@ func (w *Wallet) extendKeypool(n uint, aeskey []byte, bs *BlockStamp) error {
|
|||
if err = newaddr.encrypt(aeskey); err != nil {
|
||||
return err
|
||||
}
|
||||
addrKey := addressHashKey(newaddr.pubKeyHash[:])
|
||||
w.addrMap[addrKey] = newaddr
|
||||
a := newaddr.address(w.net)
|
||||
w.addrMap[*a] = newaddr
|
||||
newaddr.chainIndex = addr.chainIndex + 1
|
||||
w.chainIdxMap[newaddr.chainIndex] = addrKey
|
||||
w.chainIdxMap[newaddr.chainIndex] = a
|
||||
w.lastChainIdx++
|
||||
// armory does this.. but all the chaincodes are equal so why
|
||||
// not use the root's?
|
||||
|
@ -917,40 +887,22 @@ func (w *Wallet) extendKeypool(n uint, aeskey []byte, bs *BlockStamp) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// addrHashForAddress decodes and returns the address hash for a
|
||||
// payment address string, performing some basic sanity checking that it
|
||||
// matches the Bitcoin network used by the wallet.
|
||||
func (w *Wallet) addrHashForAddress(addr string) ([]byte, error) {
|
||||
addr160, net, err := btcutil.DecodeAddress(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return error if address is for the wrong Bitcoin network.
|
||||
switch {
|
||||
case net == btcutil.MainNetAddr && w.net != btcwire.MainNet:
|
||||
fallthrough
|
||||
case net == btcutil.TestNetAddr && w.net != btcwire.TestNet:
|
||||
return nil, ErrNetworkMismatch
|
||||
}
|
||||
|
||||
return addr160, nil
|
||||
}
|
||||
|
||||
// AddressKey returns the private key for a payment address stored
|
||||
// in a wallet. This can fail if the payment address is for a different
|
||||
// Bitcoin network than what this wallet uses, the address is not
|
||||
// contained in the wallet, the address does not include a public and
|
||||
// private key, or if the wallet is locked.
|
||||
func (w *Wallet) AddressKey(addr string) (key *ecdsa.PrivateKey, err error) {
|
||||
// Get address hash for payment address string.
|
||||
addr160, err := w.addrHashForAddress(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (w *Wallet) AddressKey(a btcutil.Address) (key *ecdsa.PrivateKey, err error) {
|
||||
// Currently, only P2PKH addresses are supported. This should
|
||||
// be extended to a switch-case statement when support for other
|
||||
// addresses are added.
|
||||
addr, ok := a.(*btcutil.AddressPubKeyHash)
|
||||
if !ok {
|
||||
return nil, errors.New("unsupported address")
|
||||
}
|
||||
|
||||
// Lookup address from map.
|
||||
btcaddr, ok := w.addrMap[addressHashKey(addr160)]
|
||||
btcaddr, ok := w.addrMap[*addr]
|
||||
if !ok {
|
||||
return nil, ErrAddressNotFound
|
||||
}
|
||||
|
@ -996,17 +948,19 @@ func (w *Wallet) AddressKey(addr string) (key *ecdsa.PrivateKey, err error) {
|
|||
}
|
||||
|
||||
// AddressInfo returns an AddressInfo structure for an address in a wallet.
|
||||
func (w *Wallet) AddressInfo(addr string) (*AddressInfo, error) {
|
||||
// Get address hash for addr.
|
||||
addr160, err := w.addrHashForAddress(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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.
|
||||
addr, ok := a.(*btcutil.AddressPubKeyHash)
|
||||
if !ok {
|
||||
return nil, errors.New("unsupported address")
|
||||
}
|
||||
|
||||
// Look up address by address hash.
|
||||
btcaddr, ok := w.addrMap[addressHashKey(addr160)]
|
||||
btcaddr, ok := w.addrMap[*addr]
|
||||
if !ok {
|
||||
return nil, errors.New("address not in wallet")
|
||||
return nil, ErrAddressNotFound
|
||||
}
|
||||
|
||||
return btcaddr.info(w.net)
|
||||
|
@ -1116,11 +1070,8 @@ func (w *Wallet) SetBetterEarliestBlockHeight(height int32) {
|
|||
// ImportPrivateKey creates a new encrypted btcAddress with a
|
||||
// user-provided private key and adds it to the wallet. If the
|
||||
// import is successful, the payment address string is returned.
|
||||
func (w *Wallet) ImportPrivateKey(privkey []byte, compressed bool,
|
||||
bs *BlockStamp) (string, error) {
|
||||
|
||||
// The wallet's secret will be zeroed on lock, so make a local
|
||||
// copy.
|
||||
func (w *Wallet) ImportPrivateKey(privkey []byte, compressed bool, bs *BlockStamp) (string, error) {
|
||||
// The wallet's secret will be zeroed on lock, so make a local copy.
|
||||
w.secret.Lock()
|
||||
if len(w.secret.key) != 32 {
|
||||
w.secret.Unlock()
|
||||
|
@ -1131,32 +1082,28 @@ func (w *Wallet) ImportPrivateKey(privkey []byte, compressed bool,
|
|||
w.secret.Unlock()
|
||||
|
||||
// Create new address with this private key.
|
||||
addr, err := newBtcAddress(privkey, nil, bs, compressed)
|
||||
btcaddr, err := newBtcAddress(privkey, nil, bs, compressed)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
addr.chainIndex = importedKeyChainIdx
|
||||
btcaddr.chainIndex = importedKeyChainIdx
|
||||
|
||||
// Encrypt imported address with the derived AES key.
|
||||
if err = addr.encrypt(localSecret); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Create payment address string. If this fails, return an error
|
||||
// before adding the address to the wallet.
|
||||
addr160 := addr.pubKeyHash[:]
|
||||
addrstr, err := btcutil.EncodeAddress(addr160, w.Net())
|
||||
if err != nil {
|
||||
if err = btcaddr.encrypt(localSecret); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Add address to wallet's bookkeeping structures. Adding to
|
||||
// the map will result in the imported address being serialized
|
||||
// on the next WriteTo call.
|
||||
w.addrMap[addressHashKey(addr160)] = addr
|
||||
w.importedAddrs = append(w.importedAddrs, addr)
|
||||
w.addrMap[*btcaddr.address(w.net)] = btcaddr
|
||||
w.importedAddrs = append(w.importedAddrs, btcaddr)
|
||||
|
||||
return addrstr, nil
|
||||
// Create and return encoded payment address string. Error is
|
||||
// ignored as the length of the pubkey hash and net will always
|
||||
// be valid.
|
||||
addr, _ := btcutil.NewAddressPubKeyHash(btcaddr.pubKeyHash[:], w.Net())
|
||||
return addr.String(), nil
|
||||
}
|
||||
|
||||
// CreateDate returns the Unix time of the wallet creation time. This
|
||||
|
@ -1169,7 +1116,7 @@ func (w *Wallet) CreateDate() int64 {
|
|||
// AddressInfo holds information regarding an address needed to manage
|
||||
// a complete wallet.
|
||||
type AddressInfo struct {
|
||||
Address string
|
||||
btcutil.Address
|
||||
AddrHash string
|
||||
Compressed bool
|
||||
FirstBlock int32
|
||||
|
@ -1185,12 +1132,8 @@ func (w *Wallet) SortedActiveAddresses() []*AddressInfo {
|
|||
addrs := make([]*AddressInfo, 0,
|
||||
w.highestUsed+int64(len(w.importedAddrs))+1)
|
||||
for i := int64(rootKeyChainIdx); i <= w.highestUsed; i++ {
|
||||
addr160, ok := w.chainIdxMap[i]
|
||||
if !ok {
|
||||
return addrs
|
||||
}
|
||||
addr := w.addrMap[addr160]
|
||||
info, err := addr.info(w.Net())
|
||||
a := w.chainIdxMap[i]
|
||||
info, err := w.addrMap[*a].info(w.Net())
|
||||
if err == nil {
|
||||
addrs = append(addrs, info)
|
||||
}
|
||||
|
@ -1207,15 +1150,11 @@ 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[string]*AddressInfo {
|
||||
addrs := make(map[string]*AddressInfo)
|
||||
func (w *Wallet) ActiveAddresses() map[btcutil.Address]*AddressInfo {
|
||||
addrs := make(map[btcutil.Address]*AddressInfo)
|
||||
for i := int64(rootKeyChainIdx); i <= w.highestUsed; i++ {
|
||||
addr160, ok := w.chainIdxMap[i]
|
||||
if !ok {
|
||||
return addrs
|
||||
}
|
||||
addr := w.addrMap[addr160]
|
||||
info, err := addr.info(w.Net())
|
||||
a := w.chainIdxMap[i]
|
||||
info, err := w.addrMap[*a].info(w.Net())
|
||||
if err == nil {
|
||||
addrs[info.Address] = info
|
||||
}
|
||||
|
@ -1676,7 +1615,7 @@ func newBtcAddress(privkey, iv []byte, bs *BlockStamp, compressed bool) (addr *b
|
|||
addr.privKeyCT.key = privkey
|
||||
copy(addr.initVector[:], iv)
|
||||
addr.pubKey = pubkeyFromPrivkey(privkey, compressed)
|
||||
copy(addr.pubKeyHash[:], calcHash160(addr.pubKey))
|
||||
copy(addr.pubKeyHash[:], btcutil.Hash160(addr.pubKey))
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
@ -1932,19 +1871,18 @@ func (a *btcAddress) changeEncryptionKey(oldkey, newkey []byte) error {
|
|||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
// paymentAddress returns a human readable payment address string for
|
||||
// an address.
|
||||
func (a *btcAddress) paymentAddress(net btcwire.BitcoinNet) (string, error) {
|
||||
return btcutil.EncodeAddress(a.pubKeyHash[:], net)
|
||||
// address returns a btcutil.AddressPubKeyHash for a btcAddress.
|
||||
func (a *btcAddress) address(net btcwire.BitcoinNet) *btcutil.AddressPubKeyHash {
|
||||
// error is not returned because the hash will always be 20
|
||||
// bytes, and net is assumed to be valid.
|
||||
addr, _ := btcutil.NewAddressPubKeyHash(a.pubKeyHash[:], net)
|
||||
return addr
|
||||
}
|
||||
|
||||
// info returns information about a btcAddress stored in a AddressInfo
|
||||
// struct.
|
||||
func (a *btcAddress) info(net btcwire.BitcoinNet) (*AddressInfo, error) {
|
||||
address, err := a.paymentAddress(net)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
address := a.address(net)
|
||||
|
||||
return &AddressInfo{
|
||||
Address: address,
|
||||
|
@ -2124,6 +2062,13 @@ type addrCommentEntry struct {
|
|||
comment []byte
|
||||
}
|
||||
|
||||
func (e *addrCommentEntry) address(net btcwire.BitcoinNet) *btcutil.AddressPubKeyHash {
|
||||
// error is not returned because the hash will always be 20
|
||||
// bytes, and net is assumed to be valid.
|
||||
addr, _ := btcutil.NewAddressPubKeyHash(e.pubKeyHash160[:], net)
|
||||
return addr
|
||||
}
|
||||
|
||||
func (e *addrCommentEntry) WriteTo(w io.Writer) (n int64, err error) {
|
||||
var written int64
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ func TestWalletCreationSerialization(t *testing.T) {
|
|||
[]byte("banana"), btcwire.MainNet, createdAt)
|
||||
if err != nil {
|
||||
t.Error("Error creating new wallet: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
file, err := os.Create("newwallet.bin")
|
||||
|
|
Loading…
Reference in a new issue