Complete rescan extension.
This adds to the initial rescan implementation, but switches it to rescan based on a group of addresses, rather than just one. Due to how expensive database lookups are during a rescan, wallets should take advantage of this to rescan once for all needed addresses for all accounts.
This commit is contained in:
parent
5a46de5103
commit
2511fee152
1 changed files with 123 additions and 28 deletions
147
rpcserver.go
147
rpcserver.go
|
@ -760,31 +760,99 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
|
||||||
Id: &message.Id,
|
Id: &message.Id,
|
||||||
}
|
}
|
||||||
|
|
||||||
case "rescan":
|
case "getbestblock":
|
||||||
var addr string
|
// All other "get block" commands give either the height, the
|
||||||
minblock, maxblock := int64(0), btcdb.AllShas
|
// hash, or both but require the block SHA. This gets both for
|
||||||
params, ok := message.Params.([]interface{})
|
// the best block.
|
||||||
if !ok {
|
sha, height, err := s.server.db.NewestSha()
|
||||||
return ErrBadParamsField
|
|
||||||
}
|
|
||||||
for i, v := range params {
|
|
||||||
switch v.(type) {
|
|
||||||
case string:
|
|
||||||
if i == 0 {
|
|
||||||
addr = v.(string)
|
|
||||||
}
|
|
||||||
case float64:
|
|
||||||
if i == 1 {
|
|
||||||
minblock = int64(v.(float64))
|
|
||||||
} else if i == 2 {
|
|
||||||
maxblock = int64(v.(float64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addrhash, _, err := btcutil.DecodeAddress(addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Errorf("RPCS: Error getting newest block: %v", err)
|
||||||
|
rawReply = btcjson.Reply{
|
||||||
|
Result: nil,
|
||||||
|
Error: &btcjson.ErrBestBlockHash,
|
||||||
|
Id: &message.Id,
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
rawReply = btcjson.Reply{
|
||||||
|
Result: map[string]interface{}{
|
||||||
|
"hash": sha.String(),
|
||||||
|
"height": height,
|
||||||
|
},
|
||||||
|
Id: &message.Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
case "rescan":
|
||||||
|
minblock, maxblock := int64(0), btcdb.AllShas
|
||||||
|
params, ok := message.Params.([]interface{})
|
||||||
|
if !ok || len(params) < 2 {
|
||||||
|
rawReply = btcjson.Reply{
|
||||||
|
Result: nil,
|
||||||
|
Error: &btcjson.ErrInvalidParams,
|
||||||
|
Id: &message.Id,
|
||||||
|
}
|
||||||
|
return ErrBadParamsField
|
||||||
|
}
|
||||||
|
fminblock, ok := params[0].(float64)
|
||||||
|
if !ok {
|
||||||
|
rawReply = btcjson.Reply{
|
||||||
|
Result: nil,
|
||||||
|
Error: &btcjson.ErrInvalidParams,
|
||||||
|
Id: &message.Id,
|
||||||
|
}
|
||||||
|
return ErrBadParamsField
|
||||||
|
}
|
||||||
|
minblock = int64(fminblock)
|
||||||
|
iaddrs, ok := params[1].([]interface{})
|
||||||
|
if !ok {
|
||||||
|
rawReply = btcjson.Reply{
|
||||||
|
Result: nil,
|
||||||
|
Error: &btcjson.ErrInvalidParams,
|
||||||
|
Id: &message.Id,
|
||||||
|
}
|
||||||
|
return ErrBadParamsField
|
||||||
|
}
|
||||||
|
|
||||||
|
// addrHashes holds a set of string-ified address hashes.
|
||||||
|
addrHashes := make(map[string]bool, len(iaddrs))
|
||||||
|
for i := range iaddrs {
|
||||||
|
addr, ok := iaddrs[i].(string)
|
||||||
|
if !ok {
|
||||||
|
rawReply = btcjson.Reply{
|
||||||
|
Result: nil,
|
||||||
|
Error: &btcjson.ErrInvalidParams,
|
||||||
|
Id: &message.Id,
|
||||||
|
}
|
||||||
|
return ErrBadParamsField
|
||||||
|
}
|
||||||
|
|
||||||
|
addrhash, _, err := btcutil.DecodeAddress(addr)
|
||||||
|
if err != nil {
|
||||||
|
rawReply = btcjson.Reply{
|
||||||
|
Result: nil,
|
||||||
|
Error: &btcjson.ErrInvalidParams,
|
||||||
|
Id: &message.Id,
|
||||||
|
}
|
||||||
|
return ErrBadParamsField
|
||||||
|
}
|
||||||
|
|
||||||
|
addrHashes[string(addrhash)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params) > 2 {
|
||||||
|
fmaxblock, ok := params[2].(float64)
|
||||||
|
if !ok {
|
||||||
|
rawReply = btcjson.Reply{
|
||||||
|
Result: nil,
|
||||||
|
Error: &btcjson.ErrInvalidParams,
|
||||||
|
Id: &message.Id,
|
||||||
|
}
|
||||||
|
return ErrBadParamsField
|
||||||
|
}
|
||||||
|
maxblock = int64(fmaxblock)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("RPCS: Begining rescan")
|
||||||
|
|
||||||
// FetchHeightRange may not return a complete list of block shas for
|
// FetchHeightRange may not return a complete list of block shas for
|
||||||
// the given range, so fetch range as many times as necessary.
|
// the given range, so fetch range as many times as necessary.
|
||||||
|
@ -811,14 +879,39 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
|
||||||
if txReply.Err != nil || txReply.Tx == nil {
|
if txReply.Err != nil || txReply.Tx == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, txout := range txReply.Tx.TxOut {
|
for txOutIdx, txout := range txReply.Tx.TxOut {
|
||||||
_, txaddrhash, err := btcscript.ScriptToAddrHash(txout.PkScript)
|
st, txaddrhash, err := btcscript.ScriptToAddrHash(txout.PkScript)
|
||||||
|
if st != btcscript.ScriptAddr || err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
txaddr, err := btcutil.EncodeAddress(txaddrhash, s.server.btcnet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Errorf("Error encoding address: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !bytes.Equal(addrhash, txaddrhash) {
|
if ok := addrHashes[string(txaddrhash)]; ok {
|
||||||
reply := btcjson.Reply{
|
reply := btcjson.Reply{
|
||||||
Result: txReply.Sha,
|
Result: struct {
|
||||||
|
Sender string `json:"sender"`
|
||||||
|
Receiver string `json:"receiver"`
|
||||||
|
BlockHash string `json:"blockhash"`
|
||||||
|
Height int64 `json:"height"`
|
||||||
|
TxHash string `json:"txhash"`
|
||||||
|
Index uint32 `json:"index"`
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
PkScript string `json:"pkscript"`
|
||||||
|
Spent bool `json:"spent"`
|
||||||
|
}{
|
||||||
|
Sender: "Unknown", // TODO(jrick)
|
||||||
|
Receiver: txaddr,
|
||||||
|
BlockHash: blkshalist[i].String(),
|
||||||
|
Height: blk.Height(),
|
||||||
|
TxHash: txReply.Sha.String(),
|
||||||
|
Index: uint32(txOutIdx),
|
||||||
|
Amount: txout.Value,
|
||||||
|
PkScript: btcutil.Base58Encode(txout.PkScript),
|
||||||
|
Spent: txReply.TxSpent[txOutIdx],
|
||||||
|
},
|
||||||
Error: nil,
|
Error: nil,
|
||||||
Id: &message.Id,
|
Id: &message.Id,
|
||||||
}
|
}
|
||||||
|
@ -841,6 +934,8 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
|
||||||
Id: &message.Id,
|
Id: &message.Id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debug("RPCS: Finished rescan")
|
||||||
|
|
||||||
case "notifynewtxs":
|
case "notifynewtxs":
|
||||||
params, ok := message.Params.([]interface{})
|
params, ok := message.Params.([]interface{})
|
||||||
if !ok || len(params) != 1 {
|
if !ok || len(params) != 1 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue