Updates for btcutil and btcscript's btcnet conversion.

This commit is contained in:
Josh Rickmar 2014-05-27 12:50:51 -05:00
parent 2c4ea4e4bc
commit 4495a523d8
8 changed files with 106 additions and 62 deletions

View file

@ -154,7 +154,7 @@ func (a *Account) txToPairs(pairs map[string]btcutil.Amount,
// Add outputs to new tx.
for addrStr, amt := range pairs {
addr, err := btcutil.DecodeAddress(addrStr, activeNet.Net)
addr, err := btcutil.DecodeAddress(addrStr, activeNet.Params)
if err != nil {
return nil, fmt.Errorf("cannot decode address: %s", err)
}

View file

@ -108,7 +108,8 @@ func NtfnRecvTx(n btcjson.Cmd) error {
// and record the received txout.
for outIdx, txout := range tx.MsgTx().TxOut {
var accounts []*Account
_, addrs, _, _ := btcscript.ExtractPkScriptAddrs(txout.PkScript, activeNet.Net)
_, addrs, _, _ := btcscript.ExtractPkScriptAddrs(txout.PkScript,
activeNet.Params)
for _, addr := range addrs {
a, err := AcctMgr.AccountByAddress(addr)
if err != nil {

View file

@ -277,7 +277,7 @@ func makeMultiSigScript(keys []string, nRequired int) ([]byte, *btcjson.Error) {
// mixture of the two.
for i, a := range keys {
// try to parse as pubkey address
a, err := btcutil.DecodeAddress(a, activeNet.Net)
a, err := btcutil.DecodeAddress(a, activeNet.Params)
if err != nil {
return nil, &btcjson.Error{
Code: btcjson.ErrParse.Code,
@ -301,7 +301,7 @@ func makeMultiSigScript(keys []string, nRequired int) ([]byte, *btcjson.Error) {
// This will be an addresspubkey
a, err := btcutil.DecodeAddress(apkinfo.ExportPubKey(),
activeNet.Net)
activeNet.Params)
if err != nil {
return nil, &btcjson.Error{
Code: btcjson.ErrParse.Code,
@ -384,7 +384,7 @@ func CreateMultiSig(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return nil, jsonerr
}
address, err := btcutil.NewAddressScriptHash(script, activeNet.Net)
address, err := btcutil.NewAddressScriptHash(script, activeNet.Params)
if err != nil {
// above is a valid script, shouldn't happen.
return nil, &btcjson.Error{
@ -409,7 +409,7 @@ func DumpPrivKey(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return nil, &btcjson.ErrInternal
}
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Net)
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Params)
if err != nil {
return nil, &btcjson.ErrInvalidAddressOrKey
}
@ -616,11 +616,11 @@ func GetAccount(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
}
// Is address valid?
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Net)
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Params)
if err != nil {
return nil, &btcjson.ErrInvalidAddressOrKey
}
if !addr.IsForNet(activeNet.Net) {
if !addr.IsForNet(activeNet.Params) {
return nil, &btcjson.ErrInvalidAddressOrKey
}
@ -694,7 +694,7 @@ func GetAddressBalance(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
}
// Is address valid?
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Net)
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Params)
if err != nil {
return nil, &btcjson.ErrInvalidAddressOrKey
}
@ -1220,12 +1220,12 @@ func ListAddressTransactions(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
// Decode addresses.
pkHashMap := make(map[string]struct{})
for _, addrStr := range cmd.Addresses {
addr, err := btcutil.DecodeAddress(addrStr, activeNet.Net)
addr, err := btcutil.DecodeAddress(addrStr, activeNet.Params)
if err != nil {
return nil, &btcjson.ErrInvalidAddressOrKey
}
apkh, ok := addr.(*btcutil.AddressPubKeyHash)
if !ok || !apkh.IsForNet(activeNet.Net) {
if !ok || !apkh.IsForNet(activeNet.Params) {
return nil, &btcjson.ErrInvalidAddressOrKey
}
pkHashMap[string(addr.ScriptAddress())] = struct{}{}
@ -1300,7 +1300,7 @@ func ListUnspent(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
if len(cmd.Addresses) != 0 {
// confirm that all of them are good:
for _, as := range cmd.Addresses {
a, err := btcutil.DecodeAddress(as, activeNet.Net)
a, err := btcutil.DecodeAddress(as, activeNet.Params)
if err != nil {
return nil, &btcjson.ErrInvalidAddressOrKey
}
@ -1635,7 +1635,7 @@ func SignMessage(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return nil, &btcjson.ErrInternal
}
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Net)
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Params)
if err != nil {
return nil, &btcjson.Error{
Code: btcjson.ErrParse.Code,
@ -1800,7 +1800,7 @@ func SignRawTransaction(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
}
addr, err := btcutil.NewAddressScriptHash(redeemScript,
activeNet.Net)
activeNet.Params)
if err != nil {
return nil, &btcjson.Error{
Code: btcjson.ErrDeserialization.Code,
@ -1861,7 +1861,7 @@ func SignRawTransaction(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
}
}
if !wif.IsForNet(activeNet.Net) {
if !wif.IsForNet(activeNet.Params) {
return nil, &btcjson.Error{
Code: btcjson.ErrDeserialization.Code,
Message: "key network doesn't match " +
@ -1870,7 +1870,7 @@ func SignRawTransaction(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
}
addr, err := btcutil.NewAddressPubKey(wif.SerializePubKey(),
activeNet.Net)
activeNet.Params)
if err != nil {
return nil, &btcjson.Error{
Code: btcjson.ErrDeserialization.Code,
@ -2017,7 +2017,7 @@ func SignRawTransaction(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
if (hashType&btcscript.SigHashSingle) !=
btcscript.SigHashSingle || i < len(msgTx.TxOut) {
script, err := btcscript.SignTxOutput(activeNet.Net,
script, err := btcscript.SignTxOutput(activeNet.Params,
msgTx, i, input, byte(hashType), getKey,
getScript, txIn.SignatureScript)
// Failure to sign isn't an error, it just means that
@ -2060,7 +2060,7 @@ func ValidateAddress(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
}
result := btcjson.ValidateAddressResult{}
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Net)
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Params)
if err != nil {
return result, nil
}
@ -2116,7 +2116,7 @@ func VerifyMessage(icmd btcjson.Cmd) (interface{}, *btcjson.Error) {
return nil, &btcjson.ErrInternal
}
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Net)
addr, err := btcutil.DecodeAddress(cmd.Address, activeNet.Params)
if err != nil {
return nil, &btcjson.Error{
Code: btcjson.ErrParse.Code,

View file

@ -19,15 +19,15 @@ package txstore
import (
"github.com/conformal/btcchain"
"github.com/conformal/btcjson"
"github.com/conformal/btcnet"
"github.com/conformal/btcscript"
"github.com/conformal/btcutil"
"github.com/conformal/btcwire"
)
// ToJSON returns a slice of btcjson listtransaction result types for all credits
// and debits of this transaction.
func (t *TxRecord) ToJSON(account string, chainHeight int32,
net btcwire.BitcoinNet) ([]btcjson.ListTransactionsResult, error) {
net *btcnet.Params) ([]btcjson.ListTransactionsResult, error) {
var results []btcjson.ListTransactionsResult
if d := t.Debits(); d != nil {
@ -50,7 +50,7 @@ func (t *TxRecord) ToJSON(account string, chainHeight int32,
// ToJSON returns a slice of objects that may be marshaled as a JSON array
// of JSON objects for a listtransactions RPC reply.
func (d *Debits) ToJSON(account string, chainHeight int32,
net btcwire.BitcoinNet) ([]btcjson.ListTransactionsResult, error) {
net *btcnet.Params) ([]btcjson.ListTransactionsResult, error) {
msgTx := d.Tx().MsgTx()
reply := make([]btcjson.ListTransactionsResult, 0, len(msgTx.TxOut))
@ -93,7 +93,7 @@ func (d *Debits) ToJSON(account string, chainHeight int32,
// ToJSON returns a slice of objects that may be marshaled as a JSON array
// of JSON objects for a listtransactions RPC reply.
func (c *Credit) ToJSON(account string, chainHeight int32,
net btcwire.BitcoinNet) (btcjson.ListTransactionsResult, error) {
net *btcnet.Params) (btcjson.ListTransactionsResult, error) {
msgTx := c.Tx().MsgTx()
txout := msgTx.TxOut[c.OutputIndex]

View file

@ -1395,7 +1395,7 @@ func (c *Credit) Addresses(net *btcnet.Params) (btcscript.ScriptClass,
msgTx := c.Tx().MsgTx()
pkScript := msgTx.TxOut[c.OutputIndex].PkScript
return btcscript.ExtractPkScriptAddrs(pkScript, net.Net)
return btcscript.ExtractPkScriptAddrs(pkScript, net)
}
// Change returns whether the credit is the result of a change output.

View file

@ -20,6 +20,7 @@ import (
"testing"
"time"
"github.com/conformal/btcnet"
"github.com/conformal/btcutil"
. "github.com/conformal/btcwallet/txstore"
"github.com/conformal/btcwire"
@ -108,7 +109,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
}
// Verify that we can create the JSON output without any
// errors.
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -134,7 +135,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -161,7 +162,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -188,7 +189,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -231,7 +232,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
@ -263,7 +264,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -294,7 +295,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -320,7 +321,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -348,7 +349,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -373,7 +374,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}
@ -456,7 +457,7 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
return nil, err
}
_, err = r.ToJSON("", 100, btcwire.MainNet)
_, err = r.ToJSON("", 100, &btcnet.MainNetParams)
if err != nil {
return nil, err
}

View file

@ -485,6 +485,45 @@ func (v *varEntries) ReadFrom(r io.Reader) (n int64, err error) {
}
}
// Wallet uses a custom network parameters type so it can be an io.ReaderFrom.
// Due to the way and order that wallets are currently serialized and how
// address reading requires the wallet's network parameters, setting and
// erroring on unknown wallet networks must happen on the read itself and not
// 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.
type netParams btcnet.Params
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
}
switch btcwire.BitcoinNet(binary.LittleEndian.Uint32(uint32Bytes)) {
case btcwire.MainNet:
*net = *(*netParams)(&btcnet.MainNetParams)
case btcwire.TestNet3:
*net = *(*netParams)(&btcnet.TestNet3Params)
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
}
// Stringified byte slices for use as map lookup keys.
type addressKey string
type transactionHashKey string
@ -500,7 +539,7 @@ func getAddressKey(addr btcutil.Address) addressKey {
// write to any type of byte streams, including files.
type Wallet struct {
vers version
net btcwire.BitcoinNet
net *netParams
flags walletFlags
createDate int64
name [32]byte
@ -560,7 +599,7 @@ func NewWallet(name, desc string, passphrase []byte, net *btcnet.Params,
// Create and fill wallet.
w := &Wallet{
vers: VersCurrent,
net: net.Net,
net: (*netParams)(net),
flags: walletFlags{
useEncryption: true,
watchingOnly: false,
@ -638,6 +677,7 @@ func (w *Wallet) Name() string {
func (w *Wallet) ReadFrom(r io.Reader) (n int64, err error) {
var read int64
w.net = &netParams{}
w.addrMap = make(map[addressKey]walletAddress)
w.addrCommentMap = make(map[addressKey]comment)
w.chainIdxMap = make(map[int64]btcutil.Address)
@ -653,7 +693,7 @@ func (w *Wallet) ReadFrom(r io.Reader) (n int64, err error) {
datas := []interface{}{
&id,
&w.vers,
&w.net,
w.net,
&w.flags,
make([]byte, 6), // Bytes for Armory unique ID
&w.createDate,
@ -727,7 +767,7 @@ func (w *Wallet) ReadFrom(r io.Reader) (n int64, err error) {
w.importedAddrs = append(w.importedAddrs, &e.script)
case *addrCommentEntry:
addr, err := e.address(w.net)
addr, err := e.address(w.Net())
if err != nil {
return 0, err
}
@ -802,7 +842,7 @@ func (w *Wallet) WriteTo(wtr io.Writer) (n int64, err error) {
datas := []interface{}{
&fileID,
&VersCurrent,
&w.net,
w.net,
&w.flags,
make([]byte, 6), // Bytes for Armory unique ID
&w.createDate,
@ -1195,9 +1235,9 @@ func (w *Wallet) Address(a btcutil.Address) (WalletAddress, error) {
return btcaddr, nil
}
// Net returns the bitcoin network identifier for this wallet.
func (w *Wallet) Net() btcwire.BitcoinNet {
return w.net
// Net returns the bitcoin network parameters for this wallet.
func (w *Wallet) Net() *btcnet.Params {
return (*btcnet.Params)(w.net)
}
// SetSyncStatus sets the sync status for a single wallet address. This
@ -2530,7 +2570,15 @@ func (a *btcAddress) ExportPrivKey() (*btcutil.WIF, error) {
if err != nil {
return nil, err
}
return btcutil.NewWIF((*btcec.PrivateKey)(pk), a.wallet.Net(), a.Compressed())
// 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.
wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), a.wallet.Net(), a.Compressed())
if err != nil {
panic(err)
}
return wif, nil
}
// watchingCopy creates a copy of an address without a private key.
@ -3168,7 +3216,7 @@ type addrCommentEntry struct {
comment []byte
}
func (e *addrCommentEntry) address(net btcwire.BitcoinNet) (*btcutil.AddressPubKeyHash, error) {
func (e *addrCommentEntry) address(net *btcnet.Params) (*btcutil.AddressPubKeyHash, error) {
return btcutil.NewAddressPubKeyHash(e.pubKeyHash160[:], net)
}

View file

@ -32,10 +32,10 @@ import (
"github.com/davecgh/go-spew/spew"
)
var netParams = &btcnet.MainNetParams
var tstNetParams = &btcnet.MainNetParams
func TestBtcAddressSerializer(t *testing.T) {
fakeWallet := &Wallet{net: netParams.Net}
fakeWallet := &Wallet{net: (*netParams)(tstNetParams)}
kdfp := &kdfParameters{
mem: 1024,
nIter: 5,
@ -88,7 +88,7 @@ func TestBtcAddressSerializer(t *testing.T) {
}
func TestScriptAddressSerializer(t *testing.T) {
fakeWallet := &Wallet{net: netParams.Net}
fakeWallet := &Wallet{net: (*netParams)(tstNetParams)}
script := []byte{btcscript.OP_TRUE, btcscript.OP_DUP,
btcscript.OP_DROP}
addr, err := newScriptAddress(fakeWallet, script, &BlockStamp{})
@ -120,7 +120,7 @@ func TestScriptAddressSerializer(t *testing.T) {
func TestWalletCreationSerialization(t *testing.T) {
createdAt := &BlockStamp{}
w1, err := NewWallet("banana wallet", "A wallet for testing.",
[]byte("banana"), netParams, createdAt, 100)
[]byte("banana"), tstNetParams, createdAt, 100)
if err != nil {
t.Error("Error creating new wallet: " + err.Error())
return
@ -332,7 +332,7 @@ func TestWalletPubkeyChaining(t *testing.T) {
const keypoolSize = 5
w, err := NewWallet("banana wallet", "A wallet for testing.",
[]byte("banana"), netParams, &BlockStamp{}, keypoolSize)
[]byte("banana"), tstNetParams, &BlockStamp{}, keypoolSize)
if err != nil {
t.Error("Error creating new wallet: " + err.Error())
return
@ -508,7 +508,7 @@ func TestWatchingWalletExport(t *testing.T) {
const keypoolSize = 10
createdAt := &BlockStamp{}
w, err := NewWallet("banana wallet", "A wallet for testing.",
[]byte("banana"), netParams, createdAt, keypoolSize)
[]byte("banana"), tstNetParams, createdAt, keypoolSize)
if err != nil {
t.Error("Error creating new wallet: " + err.Error())
return
@ -717,10 +717,7 @@ func TestWatchingWalletExport(t *testing.T) {
return
}
pk, _ := btcec.PrivKeyFromBytes(btcec.S256(), make([]byte, 32))
wif, err := btcutil.NewWIF(pk, netParams.Net, true)
if err != nil {
t.Fatal(err)
}
wif := btcutil.NewWIF(pk, tstNetParams, true)
if _, err := ww.ImportPrivateKey(wif, createdAt); err != ErrWalletIsWatchingOnly {
t.Errorf("Nonsensical func ImportPrivateKey returned no or incorrect error: %v", err)
return
@ -732,7 +729,7 @@ func TestImportPrivateKey(t *testing.T) {
createHeight := int32(100)
createdAt := &BlockStamp{Height: createHeight}
w, err := NewWallet("banana wallet", "A wallet for testing.",
[]byte("banana"), netParams, createdAt, keypoolSize)
[]byte("banana"), tstNetParams, createdAt, keypoolSize)
if err != nil {
t.Error("Error creating new wallet: " + err.Error())
return
@ -761,10 +758,7 @@ func TestImportPrivateKey(t *testing.T) {
}
// import priv key
wif, err := btcutil.NewWIF((*btcec.PrivateKey)(pk), netParams.Net, false)
if err != nil {
t.Fatal(err)
}
wif := btcutil.NewWIF((*btcec.PrivateKey)(pk), tstNetParams, false)
importHeight := int32(50)
importedAt := &BlockStamp{Height: importHeight}
address, err := w.ImportPrivateKey(wif, importedAt)
@ -927,7 +921,7 @@ func TestImportScript(t *testing.T) {
createHeight := int32(100)
createdAt := &BlockStamp{Height: createHeight}
w, err := NewWallet("banana wallet", "A wallet for testing.",
[]byte("banana"), netParams, createdAt, keypoolSize)
[]byte("banana"), tstNetParams, createdAt, keypoolSize)
if err != nil {
t.Error("Error creating new wallet: " + err.Error())
return
@ -1198,7 +1192,7 @@ func TestChangePassphrase(t *testing.T) {
const keypoolSize = 10
createdAt := &BlockStamp{}
w, err := NewWallet("banana wallet", "A wallet for testing.",
[]byte("banana"), netParams, createdAt, keypoolSize)
[]byte("banana"), tstNetParams, createdAt, keypoolSize)
if err != nil {
t.Error("Error creating new wallet: " + err.Error())
return