From d8b7c75b86a33f80946bdba8f24b6fd5014581a1 Mon Sep 17 00:00:00 2001 From: Chris Pacia Date: Thu, 31 Aug 2017 19:38:45 -0400 Subject: [PATCH] Interface refactor Moved some parts of the database interface as well as the OpenBazaar Wallet interface into a separate package. This commit changes the imports to point to the new package. --- api/rpc.go | 75 ++++++------- cmd/spvwallet/main.go | 15 +-- config.go | 3 +- datastore.go | 201 ----------------------------------- db/database.go | 22 ++-- db/keys.go | 30 +++--- db/keys_test.go | 32 +++--- db/stxo.go | 14 +-- db/stxo_test.go | 8 +- db/txns.go | 14 +-- db/utxo.go | 14 +-- db/utxo_test.go | 6 +- fees.go | 19 ++-- fees_test.go | 25 ++--- keys.go | 22 ++-- keys_test.go | 19 ++-- datastore_test.go => mock.go | 95 +++++++++-------- schema.go | 74 ------------- sortsignsend.go | 25 ++--- sortsignsend_test.go | 13 +-- txstore.go | 21 ++-- txstore_test.go | 45 ++++---- wallet.go | 13 +-- 23 files changed, 269 insertions(+), 536 deletions(-) delete mode 100644 datastore.go rename datastore_test.go => mock.go (72%) delete mode 100644 schema.go diff --git a/api/rpc.go b/api/rpc.go index 6adcdbd..094afd0 100644 --- a/api/rpc.go +++ b/api/rpc.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/OpenBazaar/spvwallet" "github.com/OpenBazaar/spvwallet/api/pb" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" @@ -45,11 +46,11 @@ func (s *server) Stop(ctx context.Context, in *pb.Empty) (*pb.Empty, error) { } func (s *server) CurrentAddress(ctx context.Context, in *pb.KeySelection) (*pb.Address, error) { - var purpose spvwallet.KeyPurpose + var purpose wallet.KeyPurpose if in.Purpose == pb.KeyPurpose_INTERNAL { - purpose = spvwallet.INTERNAL + purpose = wallet.INTERNAL } else if in.Purpose == pb.KeyPurpose_EXTERNAL { - purpose = spvwallet.EXTERNAL + purpose = wallet.EXTERNAL } else { return nil, errors.New("Unknown key purpose") } @@ -58,11 +59,11 @@ func (s *server) CurrentAddress(ctx context.Context, in *pb.KeySelection) (*pb.A } func (s *server) NewAddress(ctx context.Context, in *pb.KeySelection) (*pb.Address, error) { - var purpose spvwallet.KeyPurpose + var purpose wallet.KeyPurpose if in.Purpose == pb.KeyPurpose_INTERNAL { - purpose = spvwallet.INTERNAL + purpose = wallet.INTERNAL } else if in.Purpose == pb.KeyPurpose_EXTERNAL { - purpose = spvwallet.EXTERNAL + purpose = wallet.EXTERNAL } else { return nil, errors.New("Unknown key purpose") } @@ -164,14 +165,14 @@ func (s *server) GetTransaction(ctx context.Context, in *pb.Txid) (*pb.Tx, error } func (s *server) GetFeePerByte(ctx context.Context, in *pb.FeeLevelSelection) (*pb.FeePerByte, error) { - var feeLevel spvwallet.FeeLevel + var feeLevel wallet.FeeLevel switch in.FeeLevel { case pb.FeeLevel_ECONOMIC: - feeLevel = spvwallet.ECONOMIC + feeLevel = wallet.ECONOMIC case pb.FeeLevel_NORMAL: - feeLevel = spvwallet.NORMAL + feeLevel = wallet.NORMAL case pb.FeeLevel_PRIORITY: - feeLevel = spvwallet.PRIOIRTY + feeLevel = wallet.PRIOIRTY default: return nil, errors.New("Unknown fee level") } @@ -194,14 +195,14 @@ func (s *server) Spend(ctx context.Context, in *pb.SpendInfo) (*pb.Txid, error) default: return nil, errors.New("Unknown network parameters") } - var feeLevel spvwallet.FeeLevel + var feeLevel wallet.FeeLevel switch in.FeeLevel { case pb.FeeLevel_ECONOMIC: - feeLevel = spvwallet.ECONOMIC + feeLevel = wallet.ECONOMIC case pb.FeeLevel_NORMAL: - feeLevel = spvwallet.NORMAL + feeLevel = wallet.NORMAL case pb.FeeLevel_PRIORITY: - feeLevel = spvwallet.PRIOIRTY + feeLevel = wallet.PRIOIRTY default: return nil, errors.New("Unknown fee level") } @@ -298,14 +299,14 @@ func (s *server) GetConfirmations(ctx context.Context, in *pb.Txid) (*pb.Confirm } func (s *server) SweepAddress(ctx context.Context, in *pb.SweepInfo) (*pb.Txid, error) { - var utxos []spvwallet.Utxo + var utxos []wallet.Utxo for _, u := range in.Utxos { h, err := chainhash.NewHashFromStr(u.Txid) if err != nil { return nil, err } op := wire.NewOutPoint(h, u.Index) - utxo := spvwallet.Utxo{ + utxo := wallet.Utxo{ Op: *op, Value: int64(u.Value), } @@ -369,14 +370,14 @@ func (s *server) SweepAddress(ctx context.Context, in *pb.SweepInfo) (*pb.Txid, if len(in.RedeemScript) > 0 { rs = &in.RedeemScript } - var feeLevel spvwallet.FeeLevel + var feeLevel wallet.FeeLevel switch in.FeeLevel { case pb.FeeLevel_ECONOMIC: - feeLevel = spvwallet.ECONOMIC + feeLevel = wallet.ECONOMIC case pb.FeeLevel_NORMAL: - feeLevel = spvwallet.NORMAL + feeLevel = wallet.NORMAL case pb.FeeLevel_PRIORITY: - feeLevel = spvwallet.PRIOIRTY + feeLevel = wallet.PRIOIRTY default: return nil, errors.New("Unknown fee level") } @@ -393,21 +394,21 @@ func (s *server) ReSyncBlockchain(ctx context.Context, in *pb.Height) (*pb.Empty } func (s *server) CreateMultisigSignature(ctx context.Context, in *pb.CreateMultisigInfo) (*pb.SignatureList, error) { - var ins []spvwallet.TransactionInput + var ins []wallet.TransactionInput for _, input := range in.Inputs { h, err := hex.DecodeString(input.Txid) if err != nil { return nil, err } - i := spvwallet.TransactionInput{ + i := wallet.TransactionInput{ OutpointHash: h, OutpointIndex: input.Index, } ins = append(ins, i) } - var outs []spvwallet.TransactionOutput + var outs []wallet.TransactionOutput for _, output := range in.Outputs { - o := spvwallet.TransactionOutput{ + o := wallet.TransactionOutput{ ScriptPubKey: output.ScriptPubKey, Value: int64(output.Value), } @@ -473,37 +474,37 @@ func (s *server) CreateMultisigSignature(ctx context.Context, in *pb.CreateMulti } func (s *server) Multisign(ctx context.Context, in *pb.MultisignInfo) (*pb.RawTx, error) { - var ins []spvwallet.TransactionInput + var ins []wallet.TransactionInput for _, input := range in.Inputs { h, err := hex.DecodeString(input.Txid) if err != nil { return nil, err } - i := spvwallet.TransactionInput{ + i := wallet.TransactionInput{ OutpointHash: h, OutpointIndex: input.Index, } ins = append(ins, i) } - var outs []spvwallet.TransactionOutput + var outs []wallet.TransactionOutput for _, output := range in.Outputs { - o := spvwallet.TransactionOutput{ + o := wallet.TransactionOutput{ ScriptPubKey: output.ScriptPubKey, Value: int64(output.Value), } outs = append(outs, o) } - var sig1 []spvwallet.Signature + var sig1 []wallet.Signature for _, s := range in.Sig1 { - sig := spvwallet.Signature{ + sig := wallet.Signature{ InputIndex: s.Index, Signature: s.Signature, } sig1 = append(sig1, sig) } - var sig2 []spvwallet.Signature + var sig2 []wallet.Signature for _, s := range in.Sig2 { - sig := spvwallet.Signature{ + sig := wallet.Signature{ InputIndex: s.Index, Signature: s.Signature, } @@ -517,21 +518,21 @@ func (s *server) Multisign(ctx context.Context, in *pb.MultisignInfo) (*pb.RawTx } func (s *server) EstimateFee(ctx context.Context, in *pb.EstimateFeeData) (*pb.Fee, error) { - var ins []spvwallet.TransactionInput + var ins []wallet.TransactionInput for _, input := range in.Inputs { h, err := hex.DecodeString(input.Txid) if err != nil { return nil, err } - i := spvwallet.TransactionInput{ + i := wallet.TransactionInput{ OutpointHash: h, OutpointIndex: input.Index, } ins = append(ins, i) } - var outs []spvwallet.TransactionOutput + var outs []wallet.TransactionOutput for _, output := range in.Outputs { - o := spvwallet.TransactionOutput{ + o := wallet.TransactionOutput{ ScriptPubKey: output.ScriptPubKey, Value: int64(output.Value), } @@ -542,7 +543,7 @@ func (s *server) EstimateFee(ctx context.Context, in *pb.EstimateFeeData) (*pb.F } func (s *server) WalletNotify(in *pb.Empty, stream pb.API_WalletNotifyServer) error { - cb := func(tx spvwallet.TransactionCallback) { + cb := func(tx wallet.TransactionCallback) { ts, err := ptypes.TimestampProto(tx.Timestamp) if err != nil { return diff --git a/cmd/spvwallet/main.go b/cmd/spvwallet/main.go index c33bb70..e4d63c7 100644 --- a/cmd/spvwallet/main.go +++ b/cmd/spvwallet/main.go @@ -11,6 +11,7 @@ import ( "github.com/OpenBazaar/spvwallet/db" "github.com/OpenBazaar/spvwallet/gui" "github.com/OpenBazaar/spvwallet/gui/bootstrap" + wi "github.com/OpenBazaar/wallet-interface" "github.com/asticode/go-astilectron" "github.com/asticode/go-astilog" "github.com/atotto/clipboard" @@ -302,7 +303,7 @@ func (x *Start) Execute(args []string) error { } txc := make(chan uint32) - listener := func(spvwallet.TransactionCallback) { + listener := func(wi.TransactionCallback) { h, _ := wallet.ChainTip() txc <- h } @@ -371,7 +372,7 @@ func (x *Start) Execute(args []string) error { } w.Send(bootstrap.MessageOut{Name: "statsUpdate", Payload: st}) case "getAddress": - addr := wallet.CurrentAddress(spvwallet.EXTERNAL) + addr := wallet.CurrentAddress(wi.EXTERNAL) w.Send(bootstrap.MessageOut{Name: "address", Payload: addr.EncodeAddress()}) case "send": type P struct { @@ -385,16 +386,16 @@ func (x *Start) Execute(args []string) error { astilog.Errorf("Unmarshaling %s failed", m.Payload) return } - var feeLevel spvwallet.FeeLevel + var feeLevel wi.FeeLevel switch strings.ToLower(p.FeeLevel) { case "priority": - feeLevel = spvwallet.PRIOIRTY + feeLevel = wi.PRIOIRTY case "normal": - feeLevel = spvwallet.NORMAL + feeLevel = wi.NORMAL case "economic": - feeLevel = spvwallet.ECONOMIC + feeLevel = wi.ECONOMIC default: - feeLevel = spvwallet.NORMAL + feeLevel = wi.NORMAL } addr, err := btcutil.DecodeAddress(p.Address, wallet.Params()) if err != nil { diff --git a/config.go b/config.go index 744fe9b..c689c73 100644 --- a/config.go +++ b/config.go @@ -1,6 +1,7 @@ package spvwallet import ( + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" "github.com/mitchellh/go-homedir" "github.com/op/go-logging" @@ -31,7 +32,7 @@ type Config struct { RepoPath string // An implementation of the Datastore interface - DB Datastore + DB wallet.Datastore // If you wish to connect to a single trusted peer set this. Otherwise leave nil. TrustedPeer net.Addr diff --git a/datastore.go b/datastore.go deleted file mode 100644 index d7047d6..0000000 --- a/datastore.go +++ /dev/null @@ -1,201 +0,0 @@ -package spvwallet - -import ( - "bytes" - "github.com/btcsuite/btcd/btcec" - "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/wire" - "time" -) - -type Datastore interface { - Utxos() Utxos - Stxos() Stxos - Txns() Txns - Keys() Keys - WatchedScripts() WatchedScripts -} - -type Utxos interface { - // Put a utxo to the database - Put(utxo Utxo) error - - // Fetch all utxos from the db - GetAll() ([]Utxo, error) - - // Make a utxo unspendable - SetWatchOnly(utxo Utxo) error - - // Delete a utxo from the db - Delete(utxo Utxo) error -} - -type Stxos interface { - // Put a stxo to the database - Put(stxo Stxo) error - - // Fetch all stxos from the db - GetAll() ([]Stxo, error) - - // Delete a stxo from the db - Delete(stxo Stxo) error -} - -type Txns interface { - // Put a new transaction to the database - Put(txn *wire.MsgTx, value, height int, timestamp time.Time, watchOnly bool) error - - // Fetch a raw tx and it's metadata given a hash - Get(txid chainhash.Hash) (*wire.MsgTx, Txn, error) - - // Fetch all transactions from the db - GetAll(includeWatchOnly bool) ([]Txn, error) - - // Update the height of a transaction - UpdateHeight(txid chainhash.Hash, height int) error - - // Delete a transactions from the db - Delete(txid *chainhash.Hash) error -} - -// Keys provides a database interface for the wallet to save key material, track -// used keys, and manage the look ahead window. -type Keys interface { - // Put a bip32 key to the database - Put(hash160 []byte, keyPath KeyPath) error - - // Import a loose private key not part of the keychain - ImportKey(scriptAddress []byte, key *btcec.PrivateKey) error - - // Mark the script as used - MarkKeyAsUsed(scriptAddress []byte) error - - // Fetch the last index for the given key purpose - // The bool should state whether the key has been used or not - GetLastKeyIndex(purpose KeyPurpose) (int, bool, error) - - // Returns the first unused path for the given purpose - GetPathForKey(scriptAddress []byte) (KeyPath, error) - - // Returns an imported private key given a script address - GetKey(scriptAddress []byte) (*btcec.PrivateKey, error) - - // Get a list of unused key indexes for the given purpose - GetUnused(purpose KeyPurpose) ([]int, error) - - // Fetch all key paths - GetAll() ([]KeyPath, error) - - // Get the number of unused keys following the last used key - // for each key purpose. - GetLookaheadWindows() map[KeyPurpose]int -} - -type WatchedScripts interface { - // Add a script to watch - Put(scriptPubKey []byte) error - - // Return all watched scripts - GetAll() ([][]byte, error) - - // Delete a watched script - Delete(scriptPubKey []byte) error -} - -type Utxo struct { - // Previous txid and output index - Op wire.OutPoint - - // Block height where this tx was confirmed, 0 for unconfirmed - AtHeight int32 - - // The higher the better - Value int64 - - // Output script - ScriptPubkey []byte - - // If true this utxo will not be selected for spending. The primary - // purpose is track multisig UTXOs which must have separate handling - // to spend. - WatchOnly bool -} - -func (utxo *Utxo) IsEqual(alt *Utxo) bool { - if alt == nil { - return utxo == nil - } - - if !utxo.Op.Hash.IsEqual(&alt.Op.Hash) { - return false - } - - if utxo.Op.Index != alt.Op.Index { - return false - } - - if utxo.AtHeight != alt.AtHeight { - return false - } - - if utxo.Value != alt.Value { - return false - } - - if bytes.Compare(utxo.ScriptPubkey, alt.ScriptPubkey) != 0 { - return false - } - - return true -} - -type Stxo struct { - // When it used to be a UTXO - Utxo Utxo - - // The height at which it met its demise - SpendHeight int32 - - // The tx that consumed it - SpendTxid chainhash.Hash -} - -func (stxo *Stxo) IsEqual(alt *Stxo) bool { - if alt == nil { - return stxo == nil - } - - if !stxo.Utxo.IsEqual(&alt.Utxo) { - return false - } - - if stxo.SpendHeight != alt.SpendHeight { - return false - } - - if !stxo.SpendTxid.IsEqual(&alt.SpendTxid) { - return false - } - - return true -} - -type Txn struct { - // Transaction ID - Txid string - - // The value relevant to the wallet - Value int64 - - // The height at which it was mined - Height int32 - - // The time the transaction was first seen - Timestamp time.Time - - // This transaction only involves a watch only address - WatchOnly bool - - // Raw transaction bytes - Bytes []byte -} diff --git a/db/database.go b/db/database.go index 19000ef..8f7aded 100644 --- a/db/database.go +++ b/db/database.go @@ -2,7 +2,7 @@ package db import ( "database/sql" - "github.com/OpenBazaar/spvwallet" + "github.com/OpenBazaar/wallet-interface" _ "github.com/mattn/go-sqlite3" "path" "sync" @@ -12,11 +12,11 @@ import ( // This database is mostly just an example implementation used for testing. // End users are free to user their own database. type SQLiteDatastore struct { - keys spvwallet.Keys - utxos spvwallet.Utxos - stxos spvwallet.Stxos - txns spvwallet.Txns - watchedScripts spvwallet.WatchedScripts + keys wallet.Keys + utxos wallet.Utxos + stxos wallet.Stxos + txns wallet.Txns + watchedScripts wallet.WatchedScripts db *sql.DB lock *sync.RWMutex } @@ -57,19 +57,19 @@ func Create(repoPath string) (*SQLiteDatastore, error) { return sqliteDB, nil } -func (db *SQLiteDatastore) Keys() spvwallet.Keys { +func (db *SQLiteDatastore) Keys() wallet.Keys { return db.keys } -func (db *SQLiteDatastore) Utxos() spvwallet.Utxos { +func (db *SQLiteDatastore) Utxos() wallet.Utxos { return db.utxos } -func (db *SQLiteDatastore) Stxos() spvwallet.Stxos { +func (db *SQLiteDatastore) Stxos() wallet.Stxos { return db.stxos } -func (db *SQLiteDatastore) Txns() spvwallet.Txns { +func (db *SQLiteDatastore) Txns() wallet.Txns { return db.txns } -func (db *SQLiteDatastore) WatchedScripts() spvwallet.WatchedScripts { +func (db *SQLiteDatastore) WatchedScripts() wallet.WatchedScripts { return db.watchedScripts } diff --git a/db/keys.go b/db/keys.go index 1ed9443..efda201 100644 --- a/db/keys.go +++ b/db/keys.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "errors" "fmt" - "github.com/OpenBazaar/spvwallet" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/btcec" "math/rand" "strconv" @@ -17,7 +17,7 @@ type KeysDB struct { lock *sync.RWMutex } -func (k *KeysDB) Put(scriptAddress []byte, keyPath spvwallet.KeyPath) error { +func (k *KeysDB) Put(scriptAddress []byte, keyPath wallet.KeyPath) error { k.lock.Lock() defer k.lock.Unlock() tx, err := k.db.Begin() @@ -76,7 +76,7 @@ func (k *KeysDB) MarkKeyAsUsed(scriptAddress []byte) error { return nil } -func (k *KeysDB) GetLastKeyIndex(purpose spvwallet.KeyPurpose) (int, bool, error) { +func (k *KeysDB) GetLastKeyIndex(purpose wallet.KeyPurpose) (int, bool, error) { k.lock.RLock() defer k.lock.RUnlock() @@ -98,7 +98,7 @@ func (k *KeysDB) GetLastKeyIndex(purpose spvwallet.KeyPurpose) (int, bool, error return index, used, nil } -func (k *KeysDB) GetPathForKey(scriptAddress []byte) (spvwallet.KeyPath, error) { +func (k *KeysDB) GetPathForKey(scriptAddress []byte) (wallet.KeyPath, error) { k.lock.RLock() defer k.lock.RUnlock() @@ -108,10 +108,10 @@ func (k *KeysDB) GetPathForKey(scriptAddress []byte) (spvwallet.KeyPath, error) var index int err = stmt.QueryRow(hex.EncodeToString(scriptAddress)).Scan(&purpose, &index) if err != nil { - return spvwallet.KeyPath{}, errors.New("Key not found") + return wallet.KeyPath{}, errors.New("Key not found") } - p := spvwallet.KeyPath{ - Purpose: spvwallet.KeyPurpose(purpose), + p := wallet.KeyPath{ + Purpose: wallet.KeyPurpose(purpose), Index: index, } return p, nil @@ -136,7 +136,7 @@ func (k *KeysDB) GetKey(scriptAddress []byte) (*btcec.PrivateKey, error) { return key, nil } -func (k *KeysDB) GetUnused(purpose spvwallet.KeyPurpose) ([]int, error) { +func (k *KeysDB) GetUnused(purpose wallet.KeyPurpose) ([]int, error) { k.lock.RLock() defer k.lock.RUnlock() var ret []int @@ -157,10 +157,10 @@ func (k *KeysDB) GetUnused(purpose spvwallet.KeyPurpose) ([]int, error) { return ret, nil } -func (k *KeysDB) GetAll() ([]spvwallet.KeyPath, error) { +func (k *KeysDB) GetAll() ([]wallet.KeyPath, error) { k.lock.RLock() defer k.lock.RUnlock() - var ret []spvwallet.KeyPath + var ret []wallet.KeyPath stm := "select purpose, keyIndex from keys" rows, err := k.db.Query(stm) defer rows.Close() @@ -174,8 +174,8 @@ func (k *KeysDB) GetAll() ([]spvwallet.KeyPath, error) { if err := rows.Scan(&purpose, &index); err != nil { fmt.Println(err) } - p := spvwallet.KeyPath{ - Purpose: spvwallet.KeyPurpose(purpose), + p := wallet.KeyPath{ + Purpose: wallet.KeyPurpose(purpose), Index: index, } ret = append(ret, p) @@ -183,10 +183,10 @@ func (k *KeysDB) GetAll() ([]spvwallet.KeyPath, error) { return ret, nil } -func (k *KeysDB) GetLookaheadWindows() map[spvwallet.KeyPurpose]int { +func (k *KeysDB) GetLookaheadWindows() map[wallet.KeyPurpose]int { k.lock.RLock() defer k.lock.RUnlock() - windows := make(map[spvwallet.KeyPurpose]int) + windows := make(map[wallet.KeyPurpose]int) for i := 0; i < 2; i++ { stm := "select used from keys where purpose=" + strconv.Itoa(i) + " order by rowid desc" rows, err := k.db.Query(stm) @@ -205,7 +205,7 @@ func (k *KeysDB) GetLookaheadWindows() map[spvwallet.KeyPurpose]int { break } } - purpose := spvwallet.KeyPurpose(i) + purpose := wallet.KeyPurpose(i) windows[purpose] = unusedCount rows.Close() } diff --git a/db/keys_test.go b/db/keys_test.go index 09510df..ba6424f 100644 --- a/db/keys_test.go +++ b/db/keys_test.go @@ -5,7 +5,7 @@ import ( "crypto/rand" "database/sql" "encoding/hex" - "github.com/OpenBazaar/spvwallet" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/btcec" "sync" "testing" @@ -26,7 +26,7 @@ func TestGetAll(t *testing.T) { for i := 0; i < 100; i++ { b := make([]byte, 32) rand.Read(b) - err := kdb.Put(b, spvwallet.KeyPath{spvwallet.EXTERNAL, i}) + err := kdb.Put(b, wallet.KeyPath{wallet.EXTERNAL, i}) if err != nil { t.Error(err) } @@ -39,7 +39,7 @@ func TestGetAll(t *testing.T) { func TestPutKey(t *testing.T) { b := make([]byte, 32) - err := kdb.Put(b, spvwallet.KeyPath{spvwallet.EXTERNAL, 0}) + err := kdb.Put(b, wallet.KeyPath{wallet.EXTERNAL, 0}) if err != nil { t.Error(err) } @@ -112,8 +112,8 @@ func TestImportKey(t *testing.T) { func TestPutDuplicateKey(t *testing.T) { b := make([]byte, 32) - kdb.Put(b, spvwallet.KeyPath{spvwallet.EXTERNAL, 0}) - err := kdb.Put(b, spvwallet.KeyPath{spvwallet.EXTERNAL, 0}) + kdb.Put(b, wallet.KeyPath{wallet.EXTERNAL, 0}) + err := kdb.Put(b, wallet.KeyPath{wallet.EXTERNAL, 0}) if err == nil { t.Error("Expected duplicate key error") } @@ -121,7 +121,7 @@ func TestPutDuplicateKey(t *testing.T) { func TestMarkKeyAsUsed(t *testing.T) { b := make([]byte, 33) - err := kdb.Put(b, spvwallet.KeyPath{spvwallet.EXTERNAL, 0}) + err := kdb.Put(b, wallet.KeyPath{wallet.EXTERNAL, 0}) if err != nil { t.Error(err) } @@ -150,18 +150,18 @@ func TestGetLastKeyIndex(t *testing.T) { for i := 0; i < 100; i++ { b := make([]byte, 32) rand.Read(b) - err := kdb.Put(b, spvwallet.KeyPath{spvwallet.EXTERNAL, i}) + err := kdb.Put(b, wallet.KeyPath{wallet.EXTERNAL, i}) if err != nil { t.Error(err) } last = b } - idx, used, err := kdb.GetLastKeyIndex(spvwallet.EXTERNAL) + idx, used, err := kdb.GetLastKeyIndex(wallet.EXTERNAL) if err != nil || idx != 99 || used != false { t.Error("Failed to fetch correct last index") } kdb.MarkKeyAsUsed(last) - _, used, err = kdb.GetLastKeyIndex(spvwallet.EXTERNAL) + _, used, err = kdb.GetLastKeyIndex(wallet.EXTERNAL) if err != nil || used != true { t.Error("Failed to fetch correct last index") } @@ -170,7 +170,7 @@ func TestGetLastKeyIndex(t *testing.T) { func TestGetPathForKey(t *testing.T) { b := make([]byte, 32) rand.Read(b) - err := kdb.Put(b, spvwallet.KeyPath{spvwallet.EXTERNAL, 15}) + err := kdb.Put(b, wallet.KeyPath{wallet.EXTERNAL, 15}) if err != nil { t.Error(err) } @@ -178,7 +178,7 @@ func TestGetPathForKey(t *testing.T) { if err != nil { t.Error(err) } - if path.Index != 15 || path.Purpose != spvwallet.EXTERNAL { + if path.Index != 15 || path.Purpose != wallet.EXTERNAL { t.Error("Returned incorrect key path") } } @@ -218,12 +218,12 @@ func TestGetUnsed(t *testing.T) { for i := 0; i < 100; i++ { b := make([]byte, 32) rand.Read(b) - err := kdb.Put(b, spvwallet.KeyPath{spvwallet.INTERNAL, i}) + err := kdb.Put(b, wallet.KeyPath{wallet.INTERNAL, i}) if err != nil { t.Error(err) } } - idx, err := kdb.GetUnused(spvwallet.INTERNAL) + idx, err := kdb.GetUnused(wallet.INTERNAL) if err != nil { t.Error("Failed to fetch correct unused") } @@ -236,7 +236,7 @@ func TestGetLookaheadWindows(t *testing.T) { for i := 0; i < 100; i++ { b := make([]byte, 32) rand.Read(b) - err := kdb.Put(b, spvwallet.KeyPath{spvwallet.EXTERNAL, i}) + err := kdb.Put(b, wallet.KeyPath{wallet.EXTERNAL, i}) if err != nil { t.Error(err) } @@ -245,7 +245,7 @@ func TestGetLookaheadWindows(t *testing.T) { } b = make([]byte, 32) rand.Read(b) - err = kdb.Put(b, spvwallet.KeyPath{spvwallet.INTERNAL, i}) + err = kdb.Put(b, wallet.KeyPath{wallet.INTERNAL, i}) if err != nil { t.Error(err) } @@ -254,7 +254,7 @@ func TestGetLookaheadWindows(t *testing.T) { } } windows := kdb.GetLookaheadWindows() - if windows[spvwallet.EXTERNAL] != 50 || windows[spvwallet.INTERNAL] != 50 { + if windows[wallet.EXTERNAL] != 50 || windows[wallet.INTERNAL] != 50 { t.Error("Fetched incorrect lookahead windows") } diff --git a/db/stxo.go b/db/stxo.go index d3891ab..43adc50 100644 --- a/db/stxo.go +++ b/db/stxo.go @@ -3,7 +3,7 @@ package db import ( "database/sql" "encoding/hex" - "github.com/OpenBazaar/spvwallet" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "strconv" @@ -16,7 +16,7 @@ type StxoDB struct { lock *sync.RWMutex } -func (s *StxoDB) Put(stxo spvwallet.Stxo) error { +func (s *StxoDB) Put(stxo wallet.Stxo) error { s.lock.Lock() defer s.lock.Unlock() tx, _ := s.db.Begin() @@ -40,10 +40,10 @@ func (s *StxoDB) Put(stxo spvwallet.Stxo) error { return nil } -func (s *StxoDB) GetAll() ([]spvwallet.Stxo, error) { +func (s *StxoDB) GetAll() ([]wallet.Stxo, error) { s.lock.RLock() defer s.lock.RUnlock() - var ret []spvwallet.Stxo + var ret []wallet.Stxo stm := "select outpoint, value, height, scriptPubKey, watchOnly, spendHeight, spendTxid from stxos" rows, err := s.db.Query(stm) defer rows.Close() @@ -85,14 +85,14 @@ func (s *StxoDB) GetAll() ([]spvwallet.Stxo, error) { if err != nil { continue } - utxo := spvwallet.Utxo{ + utxo := wallet.Utxo{ Op: *wire.NewOutPoint(shaHash, uint32(index)), AtHeight: int32(height), Value: int64(value), ScriptPubkey: scriptBytes, WatchOnly: watchOnly, } - ret = append(ret, spvwallet.Stxo{ + ret = append(ret, wallet.Stxo{ Utxo: utxo, SpendHeight: int32(spendHeight), SpendTxid: *spentHash, @@ -101,7 +101,7 @@ func (s *StxoDB) GetAll() ([]spvwallet.Stxo, error) { return ret, nil } -func (s *StxoDB) Delete(stxo spvwallet.Stxo) error { +func (s *StxoDB) Delete(stxo wallet.Stxo) error { s.lock.Lock() defer s.lock.Unlock() outpoint := stxo.Utxo.Op.Hash.String() + ":" + strconv.Itoa(int(stxo.Utxo.Op.Index)) diff --git a/db/stxo_test.go b/db/stxo_test.go index 8816a16..9075cf9 100644 --- a/db/stxo_test.go +++ b/db/stxo_test.go @@ -4,7 +4,7 @@ import ( "bytes" "database/sql" "encoding/hex" - "github.com/OpenBazaar/spvwallet" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "strconv" @@ -13,7 +13,7 @@ import ( ) var sxdb StxoDB -var stxo spvwallet.Stxo +var stxo wallet.Stxo func init() { conn, _ := sql.Open("sqlite3", ":memory:") @@ -25,14 +25,14 @@ func init() { sh1, _ := chainhash.NewHashFromStr("e941e1c32b3dd1a68edc3af9f7fe711f35aaca60f758c2dd49561e45ca2c41c0") sh2, _ := chainhash.NewHashFromStr("82998e18760a5f6e5573cd789269e7853e3ebaba07a8df0929badd69dc644c5f") outpoint := wire.NewOutPoint(sh1, 0) - utxo := spvwallet.Utxo{ + utxo := wallet.Utxo{ Op: *outpoint, AtHeight: 300000, Value: 100000000, ScriptPubkey: []byte("scriptpubkey"), WatchOnly: false, } - stxo = spvwallet.Stxo{ + stxo = wallet.Stxo{ Utxo: utxo, SpendHeight: 300100, SpendTxid: *sh2, diff --git a/db/txns.go b/db/txns.go index 3e219b0..44d19d8 100644 --- a/db/txns.go +++ b/db/txns.go @@ -3,7 +3,7 @@ package db import ( "bytes" "database/sql" - "github.com/OpenBazaar/spvwallet" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "sync" @@ -43,10 +43,10 @@ func (t *TxnsDB) Put(txn *wire.MsgTx, value, height int, timestamp time.Time, wa return nil } -func (t *TxnsDB) Get(txid chainhash.Hash) (*wire.MsgTx, spvwallet.Txn, error) { +func (t *TxnsDB) Get(txid chainhash.Hash) (*wire.MsgTx, wallet.Txn, error) { t.lock.RLock() defer t.lock.RUnlock() - var txn spvwallet.Txn + var txn wallet.Txn stmt, err := t.db.Prepare("select tx, value, height, timestamp, watchOnly from txns where txid=?") if err != nil { return nil, txn, err @@ -68,7 +68,7 @@ func (t *TxnsDB) Get(txid chainhash.Hash) (*wire.MsgTx, spvwallet.Txn, error) { if watchOnlyInt > 0 { watchOnly = true } - txn = spvwallet.Txn{ + txn = wallet.Txn{ Txid: msgTx.TxHash().String(), Value: int64(value), Height: int32(height), @@ -78,10 +78,10 @@ func (t *TxnsDB) Get(txid chainhash.Hash) (*wire.MsgTx, spvwallet.Txn, error) { return msgTx, txn, nil } -func (t *TxnsDB) GetAll(includeWatchOnly bool) ([]spvwallet.Txn, error) { +func (t *TxnsDB) GetAll(includeWatchOnly bool) ([]wallet.Txn, error) { t.lock.RLock() defer t.lock.RUnlock() - var ret []spvwallet.Txn + var ret []wallet.Txn stm := "select tx, value, height, timestamp, watchOnly from txns" rows, err := t.db.Query(stm) if err != nil { @@ -108,7 +108,7 @@ func (t *TxnsDB) GetAll(includeWatchOnly bool) ([]spvwallet.Txn, error) { watchOnly = true } - txn := spvwallet.Txn{msgTx.TxHash().String(), int64(value), int32(height), time.Unix(int64(timestamp), 0), watchOnly, tx} + txn := wallet.Txn{msgTx.TxHash().String(), int64(value), int32(height), time.Unix(int64(timestamp), 0), watchOnly, tx} ret = append(ret, txn) } return ret, nil diff --git a/db/utxo.go b/db/utxo.go index 1ceff96..ac1b24a 100644 --- a/db/utxo.go +++ b/db/utxo.go @@ -3,7 +3,7 @@ package db import ( "database/sql" "encoding/hex" - "github.com/OpenBazaar/spvwallet" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "strconv" @@ -16,7 +16,7 @@ type UtxoDB struct { lock *sync.RWMutex } -func (u *UtxoDB) Put(utxo spvwallet.Utxo) error { +func (u *UtxoDB) Put(utxo wallet.Utxo) error { u.lock.Lock() defer u.lock.Unlock() tx, _ := u.db.Begin() @@ -40,10 +40,10 @@ func (u *UtxoDB) Put(utxo spvwallet.Utxo) error { return nil } -func (u *UtxoDB) GetAll() ([]spvwallet.Utxo, error) { +func (u *UtxoDB) GetAll() ([]wallet.Utxo, error) { u.lock.RLock() defer u.lock.RUnlock() - var ret []spvwallet.Utxo + var ret []wallet.Utxo stm := "select outpoint, value, height, scriptPubKey, watchOnly from utxos" rows, err := u.db.Query(stm) defer rows.Close() @@ -79,7 +79,7 @@ func (u *UtxoDB) GetAll() ([]spvwallet.Utxo, error) { if watchOnlyInt == 1 { watchOnly = true } - ret = append(ret, spvwallet.Utxo{ + ret = append(ret, wallet.Utxo{ Op: *wire.NewOutPoint(shaHash, uint32(index)), AtHeight: int32(height), Value: int64(value), @@ -90,7 +90,7 @@ func (u *UtxoDB) GetAll() ([]spvwallet.Utxo, error) { return ret, nil } -func (u *UtxoDB) SetWatchOnly(utxo spvwallet.Utxo) error { +func (u *UtxoDB) SetWatchOnly(utxo wallet.Utxo) error { u.lock.Lock() defer u.lock.Unlock() outpoint := utxo.Op.Hash.String() + ":" + strconv.Itoa(int(utxo.Op.Index)) @@ -101,7 +101,7 @@ func (u *UtxoDB) SetWatchOnly(utxo spvwallet.Utxo) error { return nil } -func (u *UtxoDB) Delete(utxo spvwallet.Utxo) error { +func (u *UtxoDB) Delete(utxo wallet.Utxo) error { u.lock.Lock() defer u.lock.Unlock() outpoint := utxo.Op.Hash.String() + ":" + strconv.Itoa(int(utxo.Op.Index)) diff --git a/db/utxo_test.go b/db/utxo_test.go index 4c1b4ad..d784ecf 100644 --- a/db/utxo_test.go +++ b/db/utxo_test.go @@ -4,7 +4,7 @@ import ( "bytes" "database/sql" "encoding/hex" - "github.com/OpenBazaar/spvwallet" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "strconv" @@ -13,7 +13,7 @@ import ( ) var uxdb UtxoDB -var utxo spvwallet.Utxo +var utxo wallet.Utxo func init() { conn, _ := sql.Open("sqlite3", ":memory:") @@ -24,7 +24,7 @@ func init() { } sh1, _ := chainhash.NewHashFromStr("e941e1c32b3dd1a68edc3af9f7fe711f35aaca60f758c2dd49561e45ca2c41c0") outpoint := wire.NewOutPoint(sh1, 0) - utxo = spvwallet.Utxo{ + utxo = wallet.Utxo{ Op: *outpoint, AtHeight: 300000, Value: 100000000, diff --git a/fees.go b/fees.go index 4e84dae..48c8213 100644 --- a/fees.go +++ b/fees.go @@ -2,6 +2,7 @@ package spvwallet import ( "encoding/json" + "github.com/OpenBazaar/wallet-interface" "golang.org/x/net/proxy" "net" "net/http" @@ -54,16 +55,16 @@ func NewFeeProvider(maxFee, priorityFee, normalFee, economicFee uint64, feeAPI s return &fp } -func (fp *FeeProvider) GetFeePerByte(feeLevel FeeLevel) uint64 { +func (fp *FeeProvider) GetFeePerByte(feeLevel wallet.FeeLevel) uint64 { defaultFee := func() uint64 { switch feeLevel { - case PRIOIRTY: + case wallet.PRIOIRTY: return fp.priorityFee - case NORMAL: + case wallet.NORMAL: return fp.normalFee - case ECONOMIC: + case wallet.ECONOMIC: return fp.economicFee - case FEE_BUMP: + case wallet.FEE_BUMP: return fp.priorityFee * 2 default: return fp.normalFee @@ -91,25 +92,25 @@ func (fp *FeeProvider) GetFeePerByte(feeLevel FeeLevel) uint64 { fees = fp.cache.fees } switch feeLevel { - case PRIOIRTY: + case wallet.PRIOIRTY: if fees.FastestFee > fp.maxFee || fees.FastestFee == 0 { return fp.maxFee } else { return fees.FastestFee } - case NORMAL: + case wallet.NORMAL: if fees.HalfHourFee > fp.maxFee || fees.HalfHourFee == 0 { return fp.maxFee } else { return fees.HalfHourFee } - case ECONOMIC: + case wallet.ECONOMIC: if fees.HourFee > fp.maxFee || fees.HourFee == 0 { return fp.maxFee } else { return fees.HourFee } - case FEE_BUMP: + case wallet.FEE_BUMP: if (fees.FastestFee*2) > fp.maxFee || fees.FastestFee == 0 { return fp.maxFee } else { diff --git a/fees_test.go b/fees_test.go index faabd32..633771e 100644 --- a/fees_test.go +++ b/fees_test.go @@ -2,6 +2,7 @@ package spvwallet import ( "bytes" + "github.com/OpenBazaar/wallet-interface" "net/http" "testing" ) @@ -30,46 +31,46 @@ func TestFeeProvider_GetFeePerByte(t *testing.T) { fp.httpClient = new(mockHttpClient) // Test fetch from API - if fp.GetFeePerByte(PRIOIRTY) != 450 { + if fp.GetFeePerByte(wallet.PRIOIRTY) != 450 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(NORMAL) != 420 { + if fp.GetFeePerByte(wallet.NORMAL) != 420 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(ECONOMIC) != 390 { + if fp.GetFeePerByte(wallet.ECONOMIC) != 390 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(FEE_BUMP) != 900 { + if fp.GetFeePerByte(wallet.FEE_BUMP) != 900 { t.Error("Returned incorrect fee per byte") } // Test return over max fp.maxFee = 100 - if fp.GetFeePerByte(PRIOIRTY) != 100 { + if fp.GetFeePerByte(wallet.PRIOIRTY) != 100 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(NORMAL) != 100 { + if fp.GetFeePerByte(wallet.NORMAL) != 100 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(ECONOMIC) != 100 { + if fp.GetFeePerByte(wallet.ECONOMIC) != 100 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(FEE_BUMP) != 100 { + if fp.GetFeePerByte(wallet.FEE_BUMP) != 100 { t.Error("Returned incorrect fee per byte") } // Test no API provided fp.feeAPI = "" - if fp.GetFeePerByte(PRIOIRTY) != 360 { + if fp.GetFeePerByte(wallet.PRIOIRTY) != 360 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(NORMAL) != 320 { + if fp.GetFeePerByte(wallet.NORMAL) != 320 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(ECONOMIC) != 280 { + if fp.GetFeePerByte(wallet.ECONOMIC) != 280 { t.Error("Returned incorrect fee per byte") } - if fp.GetFeePerByte(FEE_BUMP) != 720 { + if fp.GetFeePerByte(wallet.FEE_BUMP) != 720 { t.Error("Returned incorrect fee per byte") } } diff --git a/keys.go b/keys.go index e21ec01..bb0a7b6 100644 --- a/keys.go +++ b/keys.go @@ -1,6 +1,7 @@ package spvwallet import ( + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" hd "github.com/btcsuite/btcutil/hdkeychain" "github.com/btcsuite/goleveldb/leveldb/errors" @@ -8,20 +9,15 @@ import ( const LOOKAHEADWINDOW = 100 -type KeyPath struct { - Purpose KeyPurpose - Index int -} - type KeyManager struct { - datastore Keys + datastore wallet.Keys params *chaincfg.Params internalKey *hd.ExtendedKey externalKey *hd.ExtendedKey } -func NewKeyManager(db Keys, params *chaincfg.Params, masterPrivKey *hd.ExtendedKey) (*KeyManager, error) { +func NewKeyManager(db wallet.Keys, params *chaincfg.Params, masterPrivKey *hd.ExtendedKey) (*KeyManager, error) { internal, external, err := Bip44Derivation(masterPrivKey) if err != nil { return nil, err @@ -68,7 +64,7 @@ func Bip44Derivation(masterPrivKey *hd.ExtendedKey) (internal, external *hd.Exte return internal, external, nil } -func (km *KeyManager) GetCurrentKey(purpose KeyPurpose) (*hd.ExtendedKey, error) { +func (km *KeyManager) GetCurrentKey(purpose wallet.KeyPurpose) (*hd.ExtendedKey, error) { i, err := km.datastore.GetUnused(purpose) if err != nil { return nil, err @@ -79,7 +75,7 @@ func (km *KeyManager) GetCurrentKey(purpose KeyPurpose) (*hd.ExtendedKey, error) return km.generateChildKey(purpose, uint32(i[0])) } -func (km *KeyManager) GetFreshKey(purpose KeyPurpose) (*hd.ExtendedKey, error) { +func (km *KeyManager) GetFreshKey(purpose wallet.KeyPurpose) (*hd.ExtendedKey, error) { index, _, err := km.datastore.GetLastKeyIndex(purpose) var childKey *hd.ExtendedKey if err != nil { @@ -101,7 +97,7 @@ func (km *KeyManager) GetFreshKey(purpose KeyPurpose) (*hd.ExtendedKey, error) { if err != nil { return nil, err } - p := KeyPath{KeyPurpose(purpose), index} + p := wallet.KeyPath{wallet.KeyPurpose(purpose), index} err = km.datastore.Put(addr.ScriptAddress(), p) if err != nil { return nil, err @@ -153,10 +149,10 @@ func (km *KeyManager) MarkKeyAsUsed(scriptAddress []byte) error { return km.lookahead() } -func (km *KeyManager) generateChildKey(purpose KeyPurpose, index uint32) (*hd.ExtendedKey, error) { - if purpose == EXTERNAL { +func (km *KeyManager) generateChildKey(purpose wallet.KeyPurpose, index uint32) (*hd.ExtendedKey, error) { + if purpose == wallet.EXTERNAL { return km.externalKey.Child(index) - } else if purpose == INTERNAL { + } else if purpose == wallet.INTERNAL { return km.internalKey.Child(index) } return nil, errors.New("Unknown key purpose") diff --git a/keys_test.go b/keys_test.go index 598ac83..cea748c 100644 --- a/keys_test.go +++ b/keys_test.go @@ -3,6 +3,7 @@ package spvwallet import ( "bytes" "encoding/hex" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" @@ -72,7 +73,7 @@ func TestKeys_generateChildKey(t *testing.T) { if err != nil { t.Error(err) } - internalKey, err := km.generateChildKey(INTERNAL, 0) + internalKey, err := km.generateChildKey(wallet.INTERNAL, 0) internalAddr, err := internalKey.Address(&chaincfg.MainNetParams) if err != nil { t.Error(err) @@ -80,7 +81,7 @@ func TestKeys_generateChildKey(t *testing.T) { if internalAddr.String() != "16wbbYdecq9QzXdxa58q2dYXJRc8sfkE4J" { t.Error("generateChildKey returned incorrect key") } - externalKey, err := km.generateChildKey(EXTERNAL, 0) + externalKey, err := km.generateChildKey(wallet.EXTERNAL, 0) externalAddr, err := externalKey.Address(&chaincfg.MainNetParams) if err != nil { t.Error(err) @@ -127,14 +128,14 @@ func TestKeyManager_MarkKeyAsUsed(t *testing.T) { if err != nil { t.Error(err) } - i, err := km.datastore.GetUnused(EXTERNAL) + i, err := km.datastore.GetUnused(wallet.EXTERNAL) if err != nil { t.Error(err) } if len(i) == 0 { t.Error("No unused keys in database") } - key, err := km.generateChildKey(EXTERNAL, uint32(i[0])) + key, err := km.generateChildKey(wallet.EXTERNAL, uint32(i[0])) if err != nil { t.Error(err) } @@ -149,7 +150,7 @@ func TestKeyManager_MarkKeyAsUsed(t *testing.T) { if len(km.GetKeys()) != (LOOKAHEADWINDOW*2)+1 { t.Error("Failed to extend lookahead window when marking as read") } - unused, err := km.datastore.GetUnused(EXTERNAL) + unused, err := km.datastore.GetUnused(wallet.EXTERNAL) if err != nil { t.Error(err) } @@ -172,12 +173,12 @@ func TestKeyManager_GetCurrentKey(t *testing.T) { } var scriptAddress string for script, key := range mock.keys { - if key.path.Purpose == EXTERNAL && key.path.Index == 0 { + if key.path.Purpose == wallet.EXTERNAL && key.path.Index == 0 { scriptAddress = script break } } - key, err := km.GetCurrentKey(EXTERNAL) + key, err := km.GetCurrentKey(wallet.EXTERNAL) if err != nil { t.Error(err) } @@ -195,14 +196,14 @@ func TestKeyManager_GetFreshKey(t *testing.T) { if err != nil { t.Error(err) } - key, err := km.GetFreshKey(EXTERNAL) + key, err := km.GetFreshKey(wallet.EXTERNAL) if err != nil { t.Error(err) } if len(km.GetKeys()) != LOOKAHEADWINDOW*2+1 { t.Error("Failed to create additional key") } - key2, err := km.generateChildKey(EXTERNAL, 100) + key2, err := km.generateChildKey(wallet.EXTERNAL, 100) if err != nil { t.Error(err) } diff --git a/datastore_test.go b/mock.go similarity index 72% rename from datastore_test.go rename to mock.go index ff462a3..f185c5b 100644 --- a/datastore_test.go +++ b/mock.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "errors" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" @@ -14,36 +15,36 @@ import ( ) type MockDatastore struct { - keys Keys - utxos Utxos - stxos Stxos - txns Txns - watchedScripts WatchedScripts + keys wallet.Keys + utxos wallet.Utxos + stxos wallet.Stxos + txns wallet.Txns + watchedScripts wallet.WatchedScripts } -func (m *MockDatastore) Keys() Keys { +func (m *MockDatastore) Keys() wallet.Keys { return m.keys } -func (m *MockDatastore) Utxos() Utxos { +func (m *MockDatastore) Utxos() wallet.Utxos { return m.utxos } -func (m *MockDatastore) Stxos() Stxos { +func (m *MockDatastore) Stxos() wallet.Stxos { return m.stxos } -func (m *MockDatastore) Txns() Txns { +func (m *MockDatastore) Txns() wallet.Txns { return m.txns } -func (m *MockDatastore) WatchedScripts() WatchedScripts { +func (m *MockDatastore) WatchedScripts() wallet.WatchedScripts { return m.watchedScripts } type keyStoreEntry struct { scriptAddress []byte - path KeyPath + path wallet.KeyPath used bool key *btcec.PrivateKey } @@ -52,13 +53,13 @@ type mockKeyStore struct { keys map[string]*keyStoreEntry } -func (m *mockKeyStore) Put(scriptAddress []byte, keyPath KeyPath) error { +func (m *mockKeyStore) Put(scriptAddress []byte, keyPath wallet.KeyPath) error { m.keys[hex.EncodeToString(scriptAddress)] = &keyStoreEntry{scriptAddress, keyPath, false, nil} return nil } func (m *mockKeyStore) ImportKey(scriptAddress []byte, key *btcec.PrivateKey) error { - kp := KeyPath{Purpose: EXTERNAL, Index: -1} + kp := wallet.KeyPath{Purpose: wallet.EXTERNAL, Index: -1} m.keys[hex.EncodeToString(scriptAddress)] = &keyStoreEntry{scriptAddress, kp, false, key} return nil } @@ -72,7 +73,7 @@ func (m *mockKeyStore) MarkKeyAsUsed(scriptAddress []byte) error { return nil } -func (m *mockKeyStore) GetLastKeyIndex(purpose KeyPurpose) (int, bool, error) { +func (m *mockKeyStore) GetLastKeyIndex(purpose wallet.KeyPurpose) (int, bool, error) { i := -1 used := false for _, key := range m.keys { @@ -87,10 +88,10 @@ func (m *mockKeyStore) GetLastKeyIndex(purpose KeyPurpose) (int, bool, error) { return i, used, nil } -func (m *mockKeyStore) GetPathForKey(scriptAddress []byte) (KeyPath, error) { +func (m *mockKeyStore) GetPathForKey(scriptAddress []byte) (wallet.KeyPath, error) { key, ok := m.keys[hex.EncodeToString(scriptAddress)] if !ok || key.path.Index == -1 { - return KeyPath{}, errors.New("key does not exist") + return wallet.KeyPath{}, errors.New("key does not exist") } return key.path, nil } @@ -104,7 +105,7 @@ func (m *mockKeyStore) GetKey(scriptAddress []byte) (*btcec.PrivateKey, error) { return nil, errors.New("Not found") } -func (m *mockKeyStore) GetUnused(purpose KeyPurpose) ([]int, error) { +func (m *mockKeyStore) GetUnused(purpose wallet.KeyPurpose) ([]int, error) { var i []int for _, key := range m.keys { if !key.used && key.path.Purpose == purpose { @@ -115,60 +116,60 @@ func (m *mockKeyStore) GetUnused(purpose KeyPurpose) ([]int, error) { return i, nil } -func (m *mockKeyStore) GetAll() ([]KeyPath, error) { - var kp []KeyPath +func (m *mockKeyStore) GetAll() ([]wallet.KeyPath, error) { + var kp []wallet.KeyPath for _, key := range m.keys { kp = append(kp, key.path) } return kp, nil } -func (m *mockKeyStore) GetLookaheadWindows() map[KeyPurpose]int { +func (m *mockKeyStore) GetLookaheadWindows() map[wallet.KeyPurpose]int { internalLastUsed := -1 externalLastUsed := -1 for _, key := range m.keys { - if key.path.Purpose == INTERNAL && key.used && key.path.Index > internalLastUsed { + if key.path.Purpose == wallet.INTERNAL && key.used && key.path.Index > internalLastUsed { internalLastUsed = key.path.Index } - if key.path.Purpose == EXTERNAL && key.used && key.path.Index > externalLastUsed { + if key.path.Purpose == wallet.EXTERNAL && key.used && key.path.Index > externalLastUsed { externalLastUsed = key.path.Index } } internalUnused := 0 externalUnused := 0 for _, key := range m.keys { - if key.path.Purpose == INTERNAL && !key.used && key.path.Index > internalLastUsed { + if key.path.Purpose == wallet.INTERNAL && !key.used && key.path.Index > internalLastUsed { internalUnused++ } - if key.path.Purpose == EXTERNAL && !key.used && key.path.Index > externalLastUsed { + if key.path.Purpose == wallet.EXTERNAL && !key.used && key.path.Index > externalLastUsed { externalUnused++ } } - mp := make(map[KeyPurpose]int) - mp[INTERNAL] = internalUnused - mp[EXTERNAL] = externalUnused + mp := make(map[wallet.KeyPurpose]int) + mp[wallet.INTERNAL] = internalUnused + mp[wallet.EXTERNAL] = externalUnused return mp } type mockUtxoStore struct { - utxos map[string]*Utxo + utxos map[string]*wallet.Utxo } -func (m *mockUtxoStore) Put(utxo Utxo) error { +func (m *mockUtxoStore) Put(utxo wallet.Utxo) error { key := utxo.Op.Hash.String() + ":" + strconv.Itoa(int(utxo.Op.Index)) m.utxos[key] = &utxo return nil } -func (m *mockUtxoStore) GetAll() ([]Utxo, error) { - var utxos []Utxo +func (m *mockUtxoStore) GetAll() ([]wallet.Utxo, error) { + var utxos []wallet.Utxo for _, v := range m.utxos { utxos = append(utxos, *v) } return utxos, nil } -func (m *mockUtxoStore) SetWatchOnly(utxo Utxo) error { +func (m *mockUtxoStore) SetWatchOnly(utxo wallet.Utxo) error { key := utxo.Op.Hash.String() + ":" + strconv.Itoa(int(utxo.Op.Index)) u, ok := m.utxos[key] if !ok { @@ -178,7 +179,7 @@ func (m *mockUtxoStore) SetWatchOnly(utxo Utxo) error { return nil } -func (m *mockUtxoStore) Delete(utxo Utxo) error { +func (m *mockUtxoStore) Delete(utxo wallet.Utxo) error { key := utxo.Op.Hash.String() + ":" + strconv.Itoa(int(utxo.Op.Index)) _, ok := m.utxos[key] if !ok { @@ -189,23 +190,23 @@ func (m *mockUtxoStore) Delete(utxo Utxo) error { } type mockStxoStore struct { - stxos map[string]*Stxo + stxos map[string]*wallet.Stxo } -func (m *mockStxoStore) Put(stxo Stxo) error { +func (m *mockStxoStore) Put(stxo wallet.Stxo) error { m.stxos[stxo.SpendTxid.String()] = &stxo return nil } -func (m *mockStxoStore) GetAll() ([]Stxo, error) { - var stxos []Stxo +func (m *mockStxoStore) GetAll() ([]wallet.Stxo, error) { + var stxos []wallet.Stxo for _, v := range m.stxos { stxos = append(stxos, *v) } return stxos, nil } -func (m *mockStxoStore) Delete(stxo Stxo) error { +func (m *mockStxoStore) Delete(stxo wallet.Stxo) error { _, ok := m.stxos[stxo.SpendTxid.String()] if !ok { return errors.New("Not found") @@ -237,22 +238,22 @@ func (m *mockTxnStore) Put(txn *wire.MsgTx, value, height int, timestamp time.Ti return nil } -func (m *mockTxnStore) Get(txid chainhash.Hash) (*wire.MsgTx, Txn, error) { +func (m *mockTxnStore) Get(txid chainhash.Hash) (*wire.MsgTx, wallet.Txn, error) { t, ok := m.txns[txid.String()] if !ok { - return nil, Txn{}, errors.New("Not found") + return nil, wallet.Txn{}, errors.New("Not found") } var buf bytes.Buffer t.txn.Serialize(&buf) - return t.txn, Txn{txid.String(), int64(t.value), int32(t.height), t.timestamp, t.watchOnly, buf.Bytes()}, nil + return t.txn, wallet.Txn{txid.String(), int64(t.value), int32(t.height), t.timestamp, t.watchOnly, buf.Bytes()}, nil } -func (m *mockTxnStore) GetAll(includeWatchOnly bool) ([]Txn, error) { - var txns []Txn +func (m *mockTxnStore) GetAll(includeWatchOnly bool) ([]wallet.Txn, error) { + var txns []wallet.Txn for _, t := range m.txns { var buf bytes.Buffer t.txn.Serialize(&buf) - txn := Txn{t.txn.TxHash().String(), int64(t.value), int32(t.height), t.timestamp, t.watchOnly, buf.Bytes()} + txn := wallet.Txn{t.txn.TxHash().String(), int64(t.value), int32(t.height), t.timestamp, t.watchOnly, buf.Bytes()} txns = append(txns, txn) } return txns, nil @@ -308,7 +309,7 @@ func TestUtxo_IsEqual(t *testing.T) { if err != nil { t.Error(err) } - u := &Utxo{ + u := &wallet.Utxo{ Op: *wire.NewOutPoint(h, 0), ScriptPubkey: make([]byte, 32), AtHeight: 400000, @@ -356,14 +357,14 @@ func TestStxo_IsEqual(t *testing.T) { if err != nil { t.Error(err) } - u := &Utxo{ + u := &wallet.Utxo{ Op: *wire.NewOutPoint(h, 0), ScriptPubkey: make([]byte, 32), AtHeight: 400000, Value: 1000000, } h2, err := chainhash.NewHashFromStr("1f64249abbf2fcc83fc060a64f69a91391e9f5d98c5d3135fe9716838283aa4c") - s := &Stxo{ + s := &wallet.Stxo{ Utxo: *u, SpendHeight: 400001, SpendTxid: *h2, diff --git a/schema.go b/schema.go deleted file mode 100644 index b0fec6d..0000000 --- a/schema.go +++ /dev/null @@ -1,74 +0,0 @@ -package spvwallet - -import "time" - -// TODO: Eventually we will like to move of this file to a separate interface repo which this wallet -// TODO: and others (such as the openbazaar-go bitcoind wallet) can share. - -// Selecting the correct fee for a transaction can be difficult for end users. We try to simplify -// this by create three generic fee levels (the exact data for which can either be hardcoded or -// fetched via API). -type FeeLevel int - -const ( - PRIOIRTY FeeLevel = 0 - NORMAL = 1 - ECONOMIC = 2 - FEE_BUMP = 3 -) - -// The end leaves on the HD wallet have only two possible values. External keys are those given -// to other people for the purpose of receiving transactions. These may include keys used for -// refund addresses. Internal keys are used only by the wallet, primarily for change addresses -// but could also be used for shuffling around UTXOs. -type KeyPurpose int - -const ( - EXTERNAL KeyPurpose = 0 - INTERNAL = 1 -) - -// This callback is passed to any registered transaction listeners when a transaction is detected -// for the wallet. -type TransactionCallback struct { - Txid []byte - Outputs []TransactionOutput - Inputs []TransactionInput - Height int32 - Timestamp time.Time - Value int64 - WatchOnly bool -} - -type TransactionOutput struct { - ScriptPubKey []byte - Value int64 - Index uint32 -} - -type TransactionInput struct { - OutpointHash []byte - OutpointIndex uint32 - LinkedScriptPubKey []byte - Value int64 -} - -// OpenBazaar uses p2sh addresses for escrow. This object can be used to store a record of a -// transaction going into or out of such an address. Incoming transactions should have a positive -// value and be market as spent when the UXTO is spent. Outgoing transactions should have a -// negative value. The spent field isn't relevant for outgoing transactions. -type TransactionRecord struct { - Txid string - Index uint32 - Value int64 - ScriptPubKey string - Spent bool - Timestamp time.Time -} - -// This object contains a single signature for a multisig transaction. InputIndex specifies -// the index for which this signature applies. -type Signature struct { - InputIndex uint32 - Signature []byte -} diff --git a/sortsignsend.go b/sortsignsend.go index 697ce1a..5075392 100644 --- a/sortsignsend.go +++ b/sortsignsend.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "fmt" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -98,7 +99,7 @@ func (w *SPVWallet) gatherCoins() map[coinset.Coin]*hd.ExtendedKey { return m } -func (w *SPVWallet) Spend(amount int64, addr btc.Address, feeLevel FeeLevel) (*chainhash.Hash, error) { +func (w *SPVWallet) Spend(amount int64, addr btc.Address, feeLevel wallet.FeeLevel) (*chainhash.Hash, error) { tx, err := w.buildTx(amount, addr, feeLevel, nil) if err != nil { return nil, err @@ -191,7 +192,7 @@ func (w *SPVWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { if err != nil { return nil, err } - transactionID, err := w.SweepAddress([]Utxo{u}, nil, key, nil, FEE_BUMP) + transactionID, err := w.SweepAddress([]wallet.Utxo{u}, nil, key, nil, wallet.FEE_BUMP) if err != nil { return nil, err } @@ -201,7 +202,7 @@ func (w *SPVWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { return nil, BumpFeeNotFoundError } -func (w *SPVWallet) EstimateFee(ins []TransactionInput, outs []TransactionOutput, feePerByte uint64) uint64 { +func (w *SPVWallet) EstimateFee(ins []wallet.TransactionInput, outs []wallet.TransactionOutput, feePerByte uint64) uint64 { tx := new(wire.MsgTx) for _, out := range outs { output := wire.NewTxOut(out.Value, out.ScriptPubKey) @@ -277,8 +278,8 @@ func (w *SPVWallet) GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, return addr, redeemScript, nil } -func (w *SPVWallet) CreateMultisigSignature(ins []TransactionInput, outs []TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte uint64) ([]Signature, error) { - var sigs []Signature +func (w *SPVWallet) CreateMultisigSignature(ins []wallet.TransactionInput, outs []wallet.TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte uint64) ([]wallet.Signature, error) { + var sigs []wallet.Signature tx := wire.NewMsgTx(1) for _, in := range ins { ch, err := chainhash.NewHashFromStr(hex.EncodeToString(in.OutpointHash)) @@ -323,13 +324,13 @@ func (w *SPVWallet) CreateMultisigSignature(ins []TransactionInput, outs []Trans if err != nil { continue } - bs := Signature{InputIndex: uint32(i), Signature: sig} + bs := wallet.Signature{InputIndex: uint32(i), Signature: sig} sigs = append(sigs, bs) } return sigs, nil } -func (w *SPVWallet) Multisign(ins []TransactionInput, outs []TransactionOutput, sigs1 []Signature, sigs2 []Signature, redeemScript []byte, feePerByte uint64, broadcast bool) ([]byte, error) { +func (w *SPVWallet) Multisign(ins []wallet.TransactionInput, outs []wallet.TransactionOutput, sigs1 []wallet.Signature, sigs2 []wallet.Signature, redeemScript []byte, feePerByte uint64, broadcast bool) ([]byte, error) { tx := wire.NewMsgTx(1) for _, in := range ins { ch, err := chainhash.NewHashFromStr(hex.EncodeToString(in.OutpointHash)) @@ -402,12 +403,12 @@ func (w *SPVWallet) Multisign(ins []TransactionInput, outs []TransactionOutput, return buf.Bytes(), nil } -func (w *SPVWallet) SweepAddress(utxos []Utxo, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (*chainhash.Hash, error) { +func (w *SPVWallet) SweepAddress(utxos []wallet.Utxo, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wallet.FeeLevel) (*chainhash.Hash, error) { var internalAddr btc.Address if address != nil { internalAddr = *address } else { - internalAddr = w.CurrentAddress(INTERNAL) + internalAddr = w.CurrentAddress(wallet.INTERNAL) } script, err := txscript.PayToAddrScript(internalAddr) if err != nil { @@ -531,7 +532,7 @@ func (w *SPVWallet) SweepAddress(utxos []Utxo, address *btc.Address, key *hd.Ext } // TODO: once segwit activates this will need to build segwit transactions if the utxo script is a witness program -func (w *SPVWallet) buildTx(amount int64, addr btc.Address, feeLevel FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { +func (w *SPVWallet) buildTx(amount int64, addr btc.Address, feeLevel wallet.FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { // Check for dust script, _ := txscript.PayToAddrScript(addr) if txrules.IsDustAmount(btc.Amount(amount), len(script), txrules.DefaultRelayFeePerKb) { @@ -585,7 +586,7 @@ func (w *SPVWallet) buildTx(amount int64, addr btc.Address, feeLevel FeeLevel, o // Create change source changeSource := func() ([]byte, error) { - addr := w.CurrentAddress(INTERNAL) + addr := w.CurrentAddress(wallet.INTERNAL) script, err := txscript.PayToAddrScript(addr) if err != nil { return []byte{}, err @@ -628,7 +629,7 @@ func (w *SPVWallet) buildTx(amount int64, addr btc.Address, feeLevel FeeLevel, o return authoredTx.Tx, nil } -func (w *SPVWallet) GetFeePerByte(feeLevel FeeLevel) uint64 { +func (w *SPVWallet) GetFeePerByte(feeLevel wallet.FeeLevel) uint64 { return w.feeProvider.GetFeePerByte(feeLevel) } diff --git a/sortsignsend_test.go b/sortsignsend_test.go index e295643..fbfaf10 100644 --- a/sortsignsend_test.go +++ b/sortsignsend_test.go @@ -2,6 +2,7 @@ package spvwallet import ( "bytes" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" @@ -26,12 +27,12 @@ func MockWallet() *SPVWallet { } func Test_gatherCoins(t *testing.T) { - wallet := MockWallet() + w := MockWallet() h1, err := chainhash.NewHashFromStr("6f7a58ad92702601fcbaac0e039943a384f5274a205c16bb8bbab54f9ea2fbad") if err != nil { t.Error(err) } - key1, err := wallet.keyManager.GetFreshKey(EXTERNAL) + key1, err := w.keyManager.GetFreshKey(wallet.EXTERNAL) if err != nil { t.Error(err) } @@ -39,16 +40,16 @@ func Test_gatherCoins(t *testing.T) { if err != nil { t.Error(err) } - script1, err := wallet.AddressToScript(addr1) + script1, err := w.AddressToScript(addr1) if err != nil { t.Error(err) } op := wire.NewOutPoint(h1, 0) - err = wallet.txstore.Utxos().Put(Utxo{Op: *op, ScriptPubkey: script1, AtHeight: 5, Value: 10000}) + err = w.txstore.Utxos().Put(wallet.Utxo{Op: *op, ScriptPubkey: script1, AtHeight: 5, Value: 10000}) if err != nil { t.Error(err) } - coinmap := wallet.gatherCoins() + coinmap := w.gatherCoins() for coin, key := range coinmap { if !bytes.Equal(coin.PkScript(), script1) { t.Error("Pubkey script in coin is incorrect") @@ -59,7 +60,7 @@ func Test_gatherCoins(t *testing.T) { if !coin.Hash().IsEqual(h1) { t.Error("Returned incorrect hash") } - height, _ := wallet.blockchain.db.Height() + height, _ := w.blockchain.db.Height() if coin.NumConfs() != int64(height-5) { t.Error("Returned incorrect number of confirmations") } diff --git a/txstore.go b/txstore.go index 32cfe6a..6641e90 100644 --- a/txstore.go +++ b/txstore.go @@ -3,6 +3,7 @@ package spvwallet import ( "bytes" "errors" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -25,12 +26,12 @@ type TxStore struct { params *chaincfg.Params - listeners []func(TransactionCallback) + listeners []func(wallet.TransactionCallback) - Datastore + wallet.Datastore } -func NewTxStore(p *chaincfg.Params, db Datastore, keyManager *KeyManager) (*TxStore, error) { +func NewTxStore(p *chaincfg.Params, db wallet.Datastore, keyManager *KeyManager) (*TxStore, error) { txs := &TxStore{ params: p, keyManager: keyManager, @@ -234,11 +235,11 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) { // Iterate through all outputs of this tx, see if we gain cachedSha := tx.TxHash() - cb := TransactionCallback{Txid: cachedSha.CloneBytes(), Height: height} + cb := wallet.TransactionCallback{Txid: cachedSha.CloneBytes(), Height: height} value := int64(0) matchesWatchOnly := false for i, txout := range tx.TxOut { - out := TransactionOutput{ScriptPubKey: txout.PkScript, Value: txout.Value, Index: uint32(i)} + out := wallet.TransactionOutput{ScriptPubKey: txout.PkScript, Value: txout.Value, Index: uint32(i)} for _, script := range PKscripts { if bytes.Equal(txout.PkScript, script) { // new utxo found scriptAddress, _ := ts.extractScriptAddress(txout.PkScript) @@ -247,7 +248,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) { Hash: cachedSha, Index: uint32(i), } - newu := Utxo{ + newu := wallet.Utxo{ AtHeight: height, Value: txout.Value, ScriptPubkey: txout.PkScript, @@ -267,7 +268,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) { Hash: cachedSha, Index: uint32(i), } - newu := Utxo{ + newu := wallet.Utxo{ AtHeight: height, Value: txout.Value, ScriptPubkey: txout.PkScript, @@ -287,7 +288,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) { for _, txin := range tx.TxIn { for i, u := range utxos { if outPointsEqual(txin.PreviousOutPoint, u.Op) { - st := Stxo{ + st := wallet.Stxo{ Utxo: u, SpendHeight: height, SpendTxid: cachedSha, @@ -302,7 +303,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32) (uint32, error) { matchesWatchOnly = true } - in := TransactionInput{ + in := wallet.TransactionInput{ OutpointHash: u.Op.Hash.CloneBytes(), OutpointIndex: u.Op.Index, LinkedScriptPubKey: u.ScriptPubkey, @@ -368,7 +369,7 @@ func (ts *TxStore) markAsDead(txid chainhash.Hash) error { if err != nil { return err } - markStxoAsDead := func(s Stxo) error { + markStxoAsDead := func(s wallet.Stxo) error { err := ts.Stxos().Delete(s) if err != nil { return err diff --git a/txstore_test.go b/txstore_test.go index 9b50657..18a110a 100644 --- a/txstore_test.go +++ b/txstore_test.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/rand" "encoding/hex" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" @@ -16,8 +17,8 @@ import ( func createTxStore() (*TxStore, error) { mockDb := MockDatastore{ &mockKeyStore{make(map[string]*keyStoreEntry)}, - &mockUtxoStore{make(map[string]*Utxo)}, - &mockStxoStore{make(map[string]*Stxo)}, + &mockUtxoStore{make(map[string]*wallet.Utxo)}, + &mockStxoStore{make(map[string]*wallet.Stxo)}, &mockTxnStore{make(map[string]*txnStoreEntry)}, &mockWatchedScriptsStore{make(map[string][]byte)}, } @@ -96,12 +97,12 @@ func TestTxStore_GimmeFilter(t *testing.T) { t.Error(err) } op := wire.NewOutPoint(maxHash, 0) - err = txStore.Utxos().Put(Utxo{Op: *op}) + err = txStore.Utxos().Put(wallet.Utxo{Op: *op}) if err != nil { t.Error(err) } op2 := wire.NewOutPoint(maxHash, 1) - err = txStore.Stxos().Put(Stxo{Utxo: Utxo{Op: *op2}}) + err = txStore.Stxos().Put(wallet.Stxo{Utxo: wallet.Utxo{Op: *op2}}) if err != nil { t.Error(err) } @@ -177,12 +178,12 @@ func TestTxStore_GetPendingInv(t *testing.T) { } h1, err := chainhash.NewHashFromStr("6f7a58ad92702601fcbaac0e039943a384f5274a205c16bb8bbab54f9ea2fbad") op := wire.NewOutPoint(h1, 0) - err = txStore.Utxos().Put(Utxo{Op: *op}) + err = txStore.Utxos().Put(wallet.Utxo{Op: *op}) if err != nil { t.Error(err) } h2, err := chainhash.NewHashFromStr("a0d4cbcd8d0694e1132400b5e114b31bc3e0d8a2ac26e054f78727c95485b528") - err = txStore.Stxos().Put(Stxo{SpendTxid: *h2}) + err = txStore.Stxos().Put(wallet.Stxo{SpendTxid: *h2}) if err != nil { t.Error(err) } @@ -239,7 +240,7 @@ func TestTxStore_markAsDead(t *testing.T) { h1 := tx1.TxHash() op := wire.NewOutPoint(&h1, 0) - err = txStore.Utxos().Put(Utxo{Op: *op}) + err = txStore.Utxos().Put(wallet.Utxo{Op: *op}) if err != nil { t.Error(err) } @@ -280,8 +281,8 @@ func TestTxStore_markAsDead(t *testing.T) { txStore.Txns().Put(tx2, 100, 0, time.Now(), false) op = wire.NewOutPoint(&h1, 0) - st := Stxo{ - Utxo: Utxo{Op: *op}, + st := wallet.Stxo{ + Utxo: wallet.Utxo{Op: *op}, SpendHeight: 0, SpendTxid: tx2.TxHash(), } @@ -326,8 +327,8 @@ func TestTxStore_markAsDead(t *testing.T) { txStore.Txns().Put(tx2, 100, 0, time.Now(), false) op = wire.NewOutPoint(&h1, 0) - st = Stxo{ - Utxo: Utxo{Op: *op}, + st = wallet.Stxo{ + Utxo: wallet.Utxo{Op: *op}, SpendHeight: 0, SpendTxid: tx2.TxHash(), } @@ -380,8 +381,8 @@ func TestTxStore_markAsDead(t *testing.T) { txStore.Txns().Put(tx2, 100, 0, time.Now(), false) op = wire.NewOutPoint(&h1, 0) - st = Stxo{ - Utxo: Utxo{Op: *op}, + st = wallet.Stxo{ + Utxo: wallet.Utxo{Op: *op}, SpendHeight: 0, SpendTxid: tx2.TxHash(), } @@ -389,7 +390,7 @@ func TestTxStore_markAsDead(t *testing.T) { h2 := tx2.TxHash() op2 := wire.NewOutPoint(&h2, 0) - err = txStore.Utxos().Put(Utxo{Op: *op2}) + err = txStore.Utxos().Put(wallet.Utxo{Op: *op2}) if err != nil { t.Error(err) } @@ -402,8 +403,8 @@ func TestTxStore_markAsDead(t *testing.T) { txStore.Txns().Put(tx3, 100, 0, time.Now(), false) op = wire.NewOutPoint(&h2, 0) - st = Stxo{ - Utxo: Utxo{Op: *op}, + st = wallet.Stxo{ + Utxo: wallet.Utxo{Op: *op}, SpendHeight: 0, SpendTxid: tx3.TxHash(), } @@ -490,8 +491,8 @@ func TestTxStore_processReorg(t *testing.T) { h1 := tx1.TxHash() op := wire.NewOutPoint(&h1, 0) - st := Stxo{ - Utxo: Utxo{Op: *op}, + st := wallet.Stxo{ + Utxo: wallet.Utxo{Op: *op}, SpendHeight: 0, SpendTxid: tx2.TxHash(), } @@ -499,11 +500,11 @@ func TestTxStore_processReorg(t *testing.T) { h2 := tx2.TxHash() op2 := wire.NewOutPoint(&h2, 0) - txStore.Utxos().Put(Utxo{Op: *op2}) + txStore.Utxos().Put(wallet.Utxo{Op: *op2}) op = wire.NewOutPoint(&h2, 0) - st = Stxo{ - Utxo: Utxo{Op: *op}, + st = wallet.Stxo{ + Utxo: wallet.Utxo{Op: *op}, SpendHeight: 0, SpendTxid: tx3.TxHash(), } @@ -578,7 +579,7 @@ func TestTxStore_Ingest(t *testing.T) { } // Ingest output hit - key, err := txStore.keyManager.GetCurrentKey(EXTERNAL) + key, err := txStore.keyManager.GetCurrentKey(wallet.EXTERNAL) if err != nil { t.Error(err) } diff --git a/wallet.go b/wallet.go index 0884e08..6fa1626 100644 --- a/wallet.go +++ b/wallet.go @@ -2,6 +2,7 @@ package spvwallet import ( "errors" + "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -198,13 +199,13 @@ func (w *SPVWallet) ConnectedPeers() []*peer.Peer { return w.peerManager.ReadyPeers() } -func (w *SPVWallet) CurrentAddress(purpose KeyPurpose) btc.Address { +func (w *SPVWallet) CurrentAddress(purpose wallet.KeyPurpose) btc.Address { key, _ := w.keyManager.GetCurrentKey(purpose) addr, _ := key.Address(w.params) return btc.Address(addr) } -func (w *SPVWallet) NewAddress(purpose KeyPurpose) btc.Address { +func (w *SPVWallet) NewAddress(purpose wallet.KeyPurpose) btc.Address { i, _ := w.txstore.Keys().GetUnused(purpose) key, _ := w.keyManager.generateChildKey(purpose, uint32(i[1])) addr, _ := key.Address(w.params) @@ -293,11 +294,11 @@ func (w *SPVWallet) Balance() (confirmed, unconfirmed int64) { return confirmed, unconfirmed } -func (w *SPVWallet) Transactions() ([]Txn, error) { +func (w *SPVWallet) Transactions() ([]wallet.Txn, error) { return w.txstore.Txns().GetAll(false) } -func (w *SPVWallet) GetTransaction(txid chainhash.Hash) (Txn, error) { +func (w *SPVWallet) GetTransaction(txid chainhash.Hash) (wallet.Txn, error) { _, txn, err := w.txstore.Txns().Get(txid) return txn, err } @@ -314,7 +315,7 @@ func (w *SPVWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error return chainTip - uint32(txn.Height) + 1, uint32(txn.Height), nil } -func (w *SPVWallet) checkIfStxoIsConfirmed(utxo Utxo, stxos []Stxo) bool { +func (w *SPVWallet) checkIfStxoIsConfirmed(utxo wallet.Utxo, stxos []wallet.Stxo) bool { for _, stxo := range stxos { if !stxo.Utxo.WatchOnly { if stxo.SpendTxid.IsEqual(&utxo.Op.Hash) { @@ -339,7 +340,7 @@ func (w *SPVWallet) Params() *chaincfg.Params { return w.params } -func (w *SPVWallet) AddTransactionListener(callback func(TransactionCallback)) { +func (w *SPVWallet) AddTransactionListener(callback func(wallet.TransactionCallback)) { w.txstore.listeners = append(w.txstore.listeners, callback) }