From dd3813d811d85223ee67f304f874c99f5bd3b03c Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Fri, 21 Mar 2014 14:08:54 -0500 Subject: [PATCH] Bootstrap unspent outpoints for rescan requests. --- cmds.go | 66 ++++++++++++++++++++++++++++++++++++++--------- cmds_test.go | 48 +++++++++++++++++++++++++++------- test_coverage.txt | 6 ++--- 3 files changed, 96 insertions(+), 24 deletions(-) diff --git a/cmds.go b/cmds.go index fdc091607..05b97d16c 100644 --- a/cmds.go +++ b/cmds.go @@ -611,7 +611,8 @@ func (cmd *RecoverAddressesCmd) UnmarshalJSON(b []byte) error { type RescanCmd struct { id interface{} BeginBlock int32 - Addresses map[string]struct{} + Addresses []string + OutPoints []*btcwire.OutPoint EndBlock int64 // TODO: switch this and btcdb.AllShas to int32 } @@ -621,8 +622,8 @@ var _ btcjson.Cmd = &RescanCmd{} // NewRescanCmd creates a new RescanCmd, parsing the optional // arguments optArgs which may either be empty or a single upper // block height. -func NewRescanCmd(id interface{}, begin int32, addresses map[string]struct{}, - optArgs ...int64) (*RescanCmd, error) { +func NewRescanCmd(id interface{}, begin int32, addresses []string, + outpoints []*btcwire.OutPoint, optArgs ...int64) (*RescanCmd, error) { // Optional parameters set to their defaults. end := btcdb.AllShas @@ -638,6 +639,7 @@ func NewRescanCmd(id interface{}, begin int32, addresses map[string]struct{}, id: id, BeginBlock: begin, Addresses: addresses, + OutPoints: outpoints, EndBlock: end, }, nil } @@ -646,7 +648,7 @@ func NewRescanCmd(id interface{}, begin int32, addresses map[string]struct{}, // the btcjson.Cmd interface. This is used when registering the custom // command with the btcjson parser. func parseRescanCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { - if len(r.Params) < 2 { + if len(r.Params) < 3 { return nil, btcjson.ErrWrongNumberOfParams } @@ -654,16 +656,47 @@ func parseRescanCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { if !ok { return nil, errors.New("first parameter must be a number") } - iaddrs, ok := r.Params[1].(map[string]interface{}) + + iaddrs, ok := r.Params[1].([]interface{}) if !ok { - return nil, errors.New("second parameter must be a JSON object") + return nil, errors.New("second parameter must be a JSON array") } - addresses := make(map[string]struct{}, len(iaddrs)) - for addr := range iaddrs { - addresses[addr] = struct{}{} + addresses := make([]string, 0, len(iaddrs)) + for _, addr := range iaddrs { + addrStr, ok := addr.(string) + if !ok { + return nil, errors.New("address is not a string") + } + addresses = append(addresses, addrStr) } - params := make([]int64, len(r.Params[2:])) - for i, val := range r.Params[2:] { + + ops, ok := r.Params[2].([]interface{}) + if !ok { + return nil, errors.New("third parameter must be a JSON array") + } + outpoints := make([]*btcwire.OutPoint, 0, len(ops)) + for i := range ops { + op, ok := ops[i].(map[string]interface{}) + if !ok { + return nil, errors.New("outpoint is not a JSON object") + } + txHashHexStr, ok := op["hash"].(string) + if !ok { + return nil, errors.New("outpoint hash is not a string") + } + txHash, err := btcwire.NewShaHashFromStr(txHashHexStr) + if err != nil { + return nil, errors.New("outpoint hash is not a valid hex string") + } + index, ok := op["index"].(float64) + if !ok { + return nil, errors.New("outpoint index is not a number") + } + outpoints = append(outpoints, btcwire.NewOutPoint(txHash, uint32(index))) + } + + params := make([]int64, len(r.Params[3:])) + for i, val := range r.Params[3:] { fval, ok := val.(float64) if !ok { return nil, errors.New("optional parameters must " + @@ -672,7 +705,7 @@ func parseRescanCmd(r *btcjson.RawCmd) (btcjson.Cmd, error) { params[i] = int64(fval) } - return NewRescanCmd(r.Id, int32(begin), addresses, params...) + return NewRescanCmd(r.Id, int32(begin), addresses, outpoints, params...) } // Id satisifies the Cmd interface by returning the ID of the command. @@ -692,6 +725,14 @@ func (cmd *RescanCmd) Method() string { // MarshalJSON returns the JSON encoding of cmd. Part of the Cmd interface. func (cmd *RescanCmd) MarshalJSON() ([]byte, error) { + ops := make([]interface{}, 0, len(cmd.OutPoints)) + for _, op := range cmd.OutPoints { + ops = append(ops, map[string]interface{}{ + "hash": op.Hash.String(), + "index": float64(op.Index), + }) + } + // Fill a RawCmd and marshal. raw := btcjson.RawCmd{ Jsonrpc: "1.0", @@ -700,6 +741,7 @@ func (cmd *RescanCmd) MarshalJSON() ([]byte, error) { Params: []interface{}{ cmd.BeginBlock, cmd.Addresses, + ops, }, } diff --git a/cmds_test.go b/cmds_test.go index 0b048dd76..7c249bc0f 100644 --- a/cmds_test.go +++ b/cmds_test.go @@ -211,19 +211,34 @@ var cmdtests = []struct { { name: "rescan no optargs", f: func() (btcjson.Cmd, error) { - addrs := map[string]struct{}{ - "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": {}, + addrs := []string{"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH"} + ops := []*btcwire.OutPoint{ + &btcwire.OutPoint{ + Hash: [...]byte{0, 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}, + Index: 1, + }, } return NewRescanCmd( float64(1), 270000, - addrs) + addrs, + ops) }, result: &RescanCmd{ id: float64(1), BeginBlock: 270000, - Addresses: map[string]struct{}{ - "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": {}, + Addresses: []string{"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH"}, + OutPoints: []*btcwire.OutPoint{ + &btcwire.OutPoint{ + Hash: [...]byte{0, 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}, + Index: 1, + }, }, EndBlock: btcdb.AllShas, }, @@ -231,20 +246,35 @@ var cmdtests = []struct { { name: "rescan one optarg", f: func() (btcjson.Cmd, error) { - addrs := map[string]struct{}{ - "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": {}, + addrs := []string{"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH"} + ops := []*btcwire.OutPoint{ + &btcwire.OutPoint{ + Hash: [...]byte{0, 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}, + Index: 1, + }, } return NewRescanCmd( float64(1), 270000, addrs, + ops, 280000) }, result: &RescanCmd{ id: float64(1), BeginBlock: 270000, - Addresses: map[string]struct{}{ - "17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": {}, + Addresses: []string{"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH"}, + OutPoints: []*btcwire.OutPoint{ + &btcwire.OutPoint{ + Hash: [...]byte{0, 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}, + Index: 1, + }, }, EndBlock: 280000, }, diff --git a/test_coverage.txt b/test_coverage.txt index e8d23d5b3..a92549308 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,11 +1,11 @@ github.com/conformal/btcws/cmds.go init 100.00% (16/16) github.com/conformal/btcws/notifications.go init 100.00% (10/10) +github.com/conformal/btcws/cmds.go RescanCmd.MarshalJSON 100.00% (7/7) github.com/conformal/btcws/notifications.go RedeemingTxNtfn.MarshalJSON 100.00% (6/6) github.com/conformal/btcws/notifications.go RecvTxNtfn.MarshalJSON 100.00% (6/6) github.com/conformal/btcws/cmds.go ListAddressTransactionsCmd.MarshalJSON 100.00% (4/4) github.com/conformal/btcws/cmds.go ListAllTransactionsCmd.MarshalJSON 100.00% (4/4) -github.com/conformal/btcws/cmds.go RescanCmd.MarshalJSON 100.00% (4/4) github.com/conformal/btcws/cmds.go WalletIsLockedCmd.MarshalJSON 100.00% (4/4) github.com/conformal/btcws/cmds.go GetUnconfirmedBalanceCmd.MarshalJSON 100.00% (4/4) github.com/conformal/btcws/cmds.go GetAddressBalanceCmd.MarshalJSON 100.00% (4/4) @@ -92,11 +92,11 @@ github.com/conformal/btcws/cmds.go NewRescanCmd 83.33% (5/6) github.com/conformal/btcws/cmds.go NewWalletIsLockedCmd 83.33% (5/6) github.com/conformal/btcws/cmds.go NewListAllTransactionsCmd 83.33% (5/6) github.com/conformal/btcws/cmds.go NewGetAddressBalanceCmd 83.33% (5/6) -github.com/conformal/btcws/cmds.go parseRescanCmd 77.78% (14/18) github.com/conformal/btcws/cmds.go parseListAddressTransactionsCmd 76.47% (13/17) github.com/conformal/btcws/cmds.go parseNotifyNewTXsCmd 75.00% (9/12) github.com/conformal/btcws/cmds.go parseGetUnconfirmedBalanceCmd 75.00% (6/8) github.com/conformal/btcws/cmds.go parseWalletIsLockedCmd 75.00% (6/8) +github.com/conformal/btcws/cmds.go parseRescanCmd 74.36% (29/39) github.com/conformal/btcws/cmds.go NotifyNewTXsCmd.UnmarshalJSON 72.73% (8/11) github.com/conformal/btcws/notifications.go RedeemingTxNtfn.UnmarshalJSON 72.73% (8/11) github.com/conformal/btcws/cmds.go CreateEncryptedWalletCmd.UnmarshalJSON 72.73% (8/11) @@ -183,5 +183,5 @@ github.com/conformal/btcws/notifications.go AllVerboseTxNtfn.SetId 0.00% (0 github.com/conformal/btcws/notifications.go TxNtfn.SetId 0.00% (0/0) github.com/conformal/btcws/notifications.go RedeemingTxNtfn.SetId 0.00% (0/0) github.com/conformal/btcws/notifications.go AllTxNtfn.SetId 0.00% (0/0) -github.com/conformal/btcws ---------------------------------------- 66.67% (534/801) +github.com/conformal/btcws ---------------------------------------- 66.91% (552/825)