mirror of
https://github.com/muun/recovery.git
synced 2025-11-12 06:50:18 -05:00
Release v2.2.0
This commit is contained in:
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/muun/recovery/utils"
|
||||
)
|
||||
|
||||
const electrumPoolSize = 3
|
||||
const electrumPoolSize = 6
|
||||
const taskTimeout = 2 * time.Minute
|
||||
const batchSize = 100
|
||||
|
||||
@@ -35,7 +35,7 @@ const batchSize = 100
|
||||
// Electrum servers.
|
||||
type Scanner struct {
|
||||
pool *electrum.Pool
|
||||
servers *ServerProvider
|
||||
servers *electrum.ServerProvider
|
||||
log *utils.Logger
|
||||
}
|
||||
|
||||
@@ -58,10 +58,11 @@ type Utxo struct {
|
||||
// scanContext contains the synchronization objects for a single Scanner round, to manage Tasks.
|
||||
type scanContext struct {
|
||||
// Task management:
|
||||
addresses chan libwallet.MuunAddress
|
||||
results chan *scanTaskResult
|
||||
done chan struct{}
|
||||
wg *sync.WaitGroup
|
||||
addresses chan libwallet.MuunAddress
|
||||
results chan *scanTaskResult
|
||||
stopScan chan struct{}
|
||||
stopCollect chan struct{}
|
||||
wg *sync.WaitGroup
|
||||
|
||||
// Progress reporting:
|
||||
reports chan *Report
|
||||
@@ -72,7 +73,7 @@ type scanContext struct {
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
pool: electrum.NewPool(electrumPoolSize),
|
||||
servers: NewServerProvider(),
|
||||
servers: electrum.NewServerProvider(),
|
||||
log: utils.NewLogger("Scanner"),
|
||||
}
|
||||
}
|
||||
@@ -83,10 +84,11 @@ func (s *Scanner) Scan(addresses chan libwallet.MuunAddress) <-chan *Report {
|
||||
|
||||
// Create the Context that goroutines will share:
|
||||
ctx := &scanContext{
|
||||
addresses: addresses,
|
||||
results: make(chan *scanTaskResult),
|
||||
done: make(chan struct{}),
|
||||
wg: &waitGroup,
|
||||
addresses: addresses,
|
||||
results: make(chan *scanTaskResult),
|
||||
stopScan: make(chan struct{}),
|
||||
stopCollect: make(chan struct{}),
|
||||
wg: &waitGroup,
|
||||
|
||||
reports: make(chan *Report),
|
||||
reportCache: &Report{
|
||||
@@ -107,6 +109,8 @@ func (s *Scanner) startCollect(ctx *scanContext) {
|
||||
for {
|
||||
select {
|
||||
case result := <-ctx.results:
|
||||
s.log.Printf("Scanned %d, found %d (err %v)", len(result.Task.addresses), len(result.Utxos), result.Err)
|
||||
|
||||
newReport := *ctx.reportCache // create a new private copy
|
||||
ctx.reportCache = &newReport
|
||||
|
||||
@@ -114,8 +118,8 @@ func (s *Scanner) startCollect(ctx *scanContext) {
|
||||
ctx.reportCache.Err = s.log.Errorf("Scan failed: %w", result.Err)
|
||||
ctx.reports <- ctx.reportCache
|
||||
|
||||
close(ctx.done) // failed after several retries, we give up and terminate all tasks
|
||||
close(ctx.reports) // close the report channel to let callers know we're done
|
||||
close(ctx.stopScan) // failed after several retries, we give up and terminate all tasks
|
||||
close(ctx.reports) // close the report channel to let callers know we're done
|
||||
return
|
||||
}
|
||||
|
||||
@@ -123,7 +127,7 @@ func (s *Scanner) startCollect(ctx *scanContext) {
|
||||
ctx.reportCache.UtxosFound = append(ctx.reportCache.UtxosFound, result.Utxos...)
|
||||
ctx.reports <- ctx.reportCache
|
||||
|
||||
case <-ctx.done:
|
||||
case <-ctx.stopCollect:
|
||||
close(ctx.reports) // close the report channel to let callers know we're done
|
||||
return
|
||||
}
|
||||
@@ -140,7 +144,7 @@ func (s *Scanner) startScan(ctx *scanContext) {
|
||||
for batch := range batches {
|
||||
// Stop the loop until a client becomes available, or the scan is canceled:
|
||||
select {
|
||||
case <-ctx.done:
|
||||
case <-ctx.stopScan:
|
||||
return
|
||||
|
||||
case client = <-s.pool.Acquire():
|
||||
@@ -161,8 +165,8 @@ func (s *Scanner) startScan(ctx *scanContext) {
|
||||
ctx.wg.Wait()
|
||||
s.log.Printf("Scan complete")
|
||||
|
||||
// Signal to the Scanner that this Context has no more pending work:
|
||||
close(ctx.done)
|
||||
// Signal to the collector that this Context has no more pending work:
|
||||
close(ctx.stopCollect)
|
||||
}
|
||||
|
||||
func (s *Scanner) scanBatch(ctx *scanContext, client *electrum.Client, batch []libwallet.MuunAddress) {
|
||||
@@ -176,7 +180,7 @@ func (s *Scanner) scanBatch(ctx *scanContext, client *electrum.Client, batch []l
|
||||
client: client,
|
||||
addresses: batch,
|
||||
timeout: taskTimeout,
|
||||
exit: ctx.done,
|
||||
exit: ctx.stopCollect,
|
||||
}
|
||||
|
||||
// Do the thing and send back the result:
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
package scanner
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
// ServerProvider manages a rotating server list, from which callers can pull server addresses.
|
||||
type ServerProvider struct {
|
||||
nextIndex int32
|
||||
}
|
||||
|
||||
// NewServerProvider returns an initialized ServerProvider.
|
||||
func NewServerProvider() *ServerProvider {
|
||||
return &ServerProvider{-1}
|
||||
}
|
||||
|
||||
// NextServer returns an address from the rotating list. It's thread-safe.
|
||||
func (p *ServerProvider) NextServer() string {
|
||||
index := int(atomic.AddInt32(&p.nextIndex, 1))
|
||||
return PublicElectrumServers[index%len(PublicElectrumServers)]
|
||||
}
|
||||
|
||||
// PublicElectrumServers list.
|
||||
//
|
||||
// This list was taken from the `electrum` repository, keeping TLS servers and excluding onion URIs.
|
||||
// It was then sorted into sections using the `cmd/survey` program, to prioritize the more reliable
|
||||
// servers with batch support.
|
||||
//
|
||||
// See https://github.com/spesmilo/electrum/blob/master/electrum/servers.json
|
||||
// See `cmd/survey/main.go`
|
||||
//
|
||||
var PublicElectrumServers = []string{
|
||||
// With batch support:
|
||||
"electrum.hsmiths.com:50002",
|
||||
"E-X.not.fyi:50002",
|
||||
"VPS.hsmiths.com:50002",
|
||||
"btc.cihar.com:50002",
|
||||
"e.keff.org:50002",
|
||||
"electrum.qtornado.com:50002",
|
||||
"electrum.emzy.de:50002",
|
||||
"tardis.bauerj.eu:50002",
|
||||
"electrum.hodlister.co:50002",
|
||||
"electrum3.hodlister.co:50002",
|
||||
"electrum5.hodlister.co:50002",
|
||||
"fortress.qtornado.com:443",
|
||||
"electrumx.erbium.eu:50002",
|
||||
"bitcoin.lukechilds.co:50002",
|
||||
"electrum.bitkoins.nl:50512",
|
||||
|
||||
// Without batch support:
|
||||
"electrum.aantonop.com:50002",
|
||||
"electrum.blockstream.info:50002",
|
||||
"blockstream.info:700",
|
||||
|
||||
// Unclassified:
|
||||
"81-7-10-251.blue.kundencontroller.de:50002",
|
||||
"b.ooze.cc:50002",
|
||||
"bitcoin.corgi.party:50002",
|
||||
"bitcoins.sk:50002",
|
||||
"btc.xskyx.net:50002",
|
||||
"electrum.jochen-hoenicke.de:50005",
|
||||
"dragon085.startdedicated.de:50002",
|
||||
"e-1.claudioboxx.com:50002",
|
||||
"electrum-server.ninja:50002",
|
||||
"electrum-unlimited.criptolayer.net:50002",
|
||||
"electrum.eff.ro:50002",
|
||||
"electrum.festivaldelhumor.org:50002",
|
||||
"electrum.leblancnet.us:50002",
|
||||
"electrum.mindspot.org:50002",
|
||||
"electrum.taborsky.cz:50002",
|
||||
"electrum.villocq.com:50002",
|
||||
"electrum2.eff.ro:50002",
|
||||
"electrum2.villocq.com:50002",
|
||||
"electrumx.bot.nu:50002",
|
||||
"electrumx.ddns.net:50002",
|
||||
"electrumx.ftp.sh:50002",
|
||||
"electrumx.soon.it:50002",
|
||||
"elx01.knas.systems:50002",
|
||||
"fedaykin.goip.de:50002",
|
||||
"fn.48.org:50002",
|
||||
"ndnd.selfhost.eu:50002",
|
||||
"orannis.com:50002",
|
||||
"rbx.curalle.ovh:50002",
|
||||
"technetium.network:50002",
|
||||
"tomscryptos.com:50002",
|
||||
"ulrichard.ch:50002",
|
||||
"vmd27610.contaboserver.net:50002",
|
||||
"vmd30612.contaboserver.net:50002",
|
||||
"xray587.startdedicated.de:50002",
|
||||
"yuio.top:50002",
|
||||
"bitcoin.dragon.zone:50004",
|
||||
"ecdsa.net:110",
|
||||
"btc.usebsv.com:50006",
|
||||
"e2.keff.org:50002",
|
||||
"electrumx.electricnewyear.net:50002",
|
||||
"green-gold.westeurope.cloudapp.azure.com:56002",
|
||||
"electrumx-core.1209k.com:50002",
|
||||
"bitcoin.aranguren.org:50002",
|
||||
}
|
||||
@@ -5,15 +5,15 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/muun/libwallet"
|
||||
"github.com/muun/libwallet/btcsuitew/btcutilw"
|
||||
"github.com/muun/libwallet/btcsuitew/txscriptw"
|
||||
"github.com/muun/recovery/electrum"
|
||||
)
|
||||
|
||||
// scanTask encapsulates a parallelizable Scanner unit of work.
|
||||
type scanTask struct {
|
||||
servers *ServerProvider
|
||||
servers *electrum.ServerProvider
|
||||
client *electrum.Client
|
||||
addresses []libwallet.MuunAddress
|
||||
timeout time.Duration
|
||||
@@ -180,12 +180,12 @@ func getOutputScripts(addresses []libwallet.MuunAddress) ([][]byte, error) {
|
||||
for i, address := range addresses {
|
||||
rawAddress := address.Address()
|
||||
|
||||
decodedAddress, err := btcutil.DecodeAddress(rawAddress, &chaincfg.MainNetParams)
|
||||
decodedAddress, err := btcutilw.DecodeAddress(rawAddress, &chaincfg.MainNetParams)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to decode address %s: %w", rawAddress, err)
|
||||
}
|
||||
|
||||
outputScript, err := txscript.PayToAddrScript(decodedAddress)
|
||||
outputScript, err := txscriptw.PayToAddrScript(decodedAddress)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to craft script for %s: %w", rawAddress, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user