Skip to content

Commit

Permalink
Release 2.2.4
Browse files Browse the repository at this point in the history
  • Loading branch information
champo committed Feb 20, 2023
1 parent ed2c88a commit 72f9f69
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 97 deletions.
21 changes: 18 additions & 3 deletions electrum/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Client struct {
nextRequestID int
conn net.Conn
log *utils.Logger
requireTls bool
}

// Request models the structure of all Electrum protocol requests.
Expand Down Expand Up @@ -110,9 +111,10 @@ type ServerFeatures struct {
type Param = interface{}

// NewClient creates an initialized Client instance.
func NewClient() *Client {
func NewClient(requireTls bool) *Client {
return &Client{
log: utils.NewLogger(defaultLoggerTag),
log: utils.NewLogger(defaultLoggerTag),
requireTls: requireTls,
}
}

Expand Down Expand Up @@ -334,6 +336,9 @@ func (c *Client) ListUnspentBatch(indexHashes []string) ([][]UnspentRef, error)
}

func (c *Client) establishConnection() error {
// We first try to connect over TCP+TLS
// If we fail and requireTls is false, we try over TCP

// TODO: check if insecure is necessary
config := &tls.Config{
InsecureSkipVerify: true,
Expand All @@ -343,12 +348,22 @@ func (c *Client) establishConnection() error {
Timeout: connectionTimeout,
}

conn, err := tls.DialWithDialer(dialer, "tcp", c.Server, config)
tlsConn, err := tls.DialWithDialer(dialer, "tcp", c.Server, config)
if err == nil {
c.conn = tlsConn
return nil
}
if c.requireTls {
return err
}

conn, err := net.DialTimeout("tcp", c.Server, connectionTimeout)
if err != nil {
return err
}

c.conn = conn

return nil
}

Expand Down
4 changes: 2 additions & 2 deletions electrum/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ type Pool struct {
}

// NewPool creates an initialized Pool with a `size` number of clients.
func NewPool(size int) *Pool {
func NewPool(size int, requireTls bool) *Pool {
nextClient := make(chan *Client, size)

for i := 0; i < size; i++ {
nextClient <- NewClient()
nextClient <- NewClient(requireTls)
}

return &Pool{nextClient}
Expand Down
143 changes: 74 additions & 69 deletions electrum/servers.go

Large diffs are not rendered by default.

81 changes: 71 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,31 @@ import (
"github.com/muun/libwallet"
"github.com/muun/libwallet/btcsuitew/btcutilw"
"github.com/muun/libwallet/emergencykit"
"github.com/muun/recovery/electrum"
"github.com/muun/recovery/scanner"
"github.com/muun/recovery/utils"
)

const electrumPoolSize = 6

var debugOutputStream = bytes.NewBuffer(nil)

type config struct {
generateContacts bool
providedElectrum string
usesProvidedElectrum bool
onlyScan bool
}

func main() {
utils.SetOutputStream(debugOutputStream)

var generateContacts bool
var config config

// Pick up command-line arguments:
flag.BoolVar(&generateContacts, "generate-contacts", false, "Generate contact addresses")
flag.BoolVar(&config.generateContacts, "generate-contacts", false, "Generate contact addresses")
flag.StringVar(&config.providedElectrum, "electrum-server", "", "Connect to this electrum server to find funds")
flag.BoolVar(&config.onlyScan, "only-scan", false, "Only scan for UTXOs without generating a transaction")
flag.Usage = printUsage
flag.Parse()
args := flag.Args()
Expand All @@ -40,6 +52,11 @@ func main() {
// Welcome!
printWelcomeMessage()

config.usesProvidedElectrum = len(strings.TrimSpace(config.providedElectrum)) > 0
if config.usesProvidedElectrum {
validateProvidedElectrum(config.providedElectrum)
}

// We're going to need a few things to move forward with the recovery process. Let's make a list
// so we keep them in mind:
var recoveryCode string
Expand All @@ -62,25 +79,41 @@ func main() {

decryptedKeys[0].Key.Path = "m/1'/1'" // a little adjustment for legacy users.

// Finally, we need the destination address to sweep the funds:
destinationAddress = readAddress()
if !config.onlyScan {
// Finally, we need the destination address to sweep the funds:
destinationAddress = readAddress()
}

sayBlock(`
Starting scan of all possible addresses. This will take a few minutes.
`)

doRecovery(decryptedKeys, destinationAddress, generateContacts)
doRecovery(decryptedKeys, destinationAddress, config)

sayBlock("We appreciate all kinds of feedback. If you have any, send it to {blue contact@muun.com}\n")
}

// doRecovery runs the scan & sweep process, and returns the ID of the broadcasted transaction.
func doRecovery(
decryptedKeys []*libwallet.DecryptedPrivateKey, destinationAddress btcutil.Address, generateContacts bool,
decryptedKeys []*libwallet.DecryptedPrivateKey,
destinationAddress btcutil.Address,
config config,
) {

addrGen := NewAddressGenerator(decryptedKeys[0].Key, decryptedKeys[1].Key, generateContacts)
utxoScanner := scanner.NewScanner()
addrGen := NewAddressGenerator(decryptedKeys[0].Key, decryptedKeys[1].Key, config.generateContacts)

var electrumProvider *electrum.ServerProvider
if config.usesProvidedElectrum {
electrumProvider = electrum.NewServerProvider([]string{
config.providedElectrum,
})
} else {
electrumProvider = electrum.NewServerProvider(electrum.PublicServers)
}

connectionPool := electrum.NewPool(electrumPoolSize, !config.usesProvidedElectrum)

utxoScanner := scanner.NewScanner(connectionPool, electrumProvider)

addresses := addrGen.Stream()

Expand Down Expand Up @@ -122,6 +155,9 @@ func doRecovery(
}

say("\n— {white %d} sats total\n", total)
if config.onlyScan {
return
}

txOutputAmount, txWeightInBytes, err := sweeper.GetSweepTxAmountAndWeightInBytes(utxos)
if err != nil {
Expand All @@ -145,11 +181,36 @@ func doRecovery(

sayBlock(`
Transaction sent! You can check the status here: https://mempool.space/tx/%v
(it will appear in Blockstream after a short delay)
(it will appear in mempool.space after a short delay)
`, sweepTx.TxHash().String())
}

func validateProvidedElectrum(providedElectrum string) {
client := electrum.NewClient(false)
err := client.Connect(providedElectrum)
defer func(client *electrum.Client) {
_ = client.Disconnect()
}(client)

if err != nil {
sayBlock(`
{red Error!}
The Recovery Tool couldn't connect to the provided Electrum server %v.
If the problem persists, contact {blue support@muun.com}.
――― {white error report} ―――
%v
――――――――――――――――――――
We're always there to help.
`, providedElectrum, err)

os.Exit(2)
}
}

func exitWithError(err error) {
sayBlock(`
{red Error!}
Expand Down Expand Up @@ -351,7 +412,7 @@ func readAddress() btcutil.Address {
func readFee(totalBalance, weight int64) int64 {
sayBlock(`
{yellow Enter the fee rate (sats/byte)}
Your transaction weighs %v bytes. You can get suggestions in https://bitcoinfees.earn.com/#fees
Your transaction weighs %v bytes. You can get suggestions in https://mempool.space/ under "Transaction fees".
`, weight)

var userInput string
Expand Down
7 changes: 3 additions & 4 deletions scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/muun/recovery/utils"
)

const electrumPoolSize = 6
const taskTimeout = 15 * time.Minute
const batchSize = 100

Expand Down Expand Up @@ -70,10 +69,10 @@ type scanContext struct {
}

// NewScanner creates an initialized Scanner.
func NewScanner() *Scanner {
func NewScanner(connectionPool *electrum.Pool, electrumProvider *electrum.ServerProvider) *Scanner {
return &Scanner{
pool: electrum.NewPool(electrumPoolSize),
servers: electrum.NewServerProvider(),
pool: connectionPool,
servers: electrumProvider,
log: utils.NewLogger("Scanner"),
}
}
Expand Down
12 changes: 6 additions & 6 deletions survey/survey.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type surveyTask struct {
}

// Values to check whether we're in the same chain (in a previous version, SV servers snuck in)
var mainnetSomeTx = "1712426823cc94935287a6834f7982723fbb5c808cbe00ec2cf3f582582be4c5"
var mainnetSomeTx = "985eb411473fa1bbd73efa5e3685edc00366c86b8d4d3f5b969ad59c23f4d959"
var mainnetGenesisHash = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"

func NewSurvey(config *Config) *Survey {
Expand Down Expand Up @@ -194,7 +194,7 @@ func (s *Survey) processTask(task *surveyTask) *Result {

// testConnection returns the server implementation, protocol version and time to connect
func testConnection(task *surveyTask) (string, string, time.Duration, error) {
client := electrum.NewClient()
client := electrum.NewClient(true)

start := time.Now()
err := client.Connect(task.server)
Expand All @@ -207,7 +207,7 @@ func testConnection(task *surveyTask) (string, string, time.Duration, error) {

// testsBlockchain returns whether this server is operating on Bitcoin mainnet
func testBitcoinMainnet(task *surveyTask) (bool, error) {
client := electrum.NewClient()
client := electrum.NewClient(true)

err := client.Connect(task.server)
if err != nil {
Expand All @@ -229,7 +229,7 @@ func testBitcoinMainnet(task *surveyTask) (bool, error) {

// testBatchSupport returns whether the server successfully responded to a batched request
func testBatchSupport(task *surveyTask) (bool, error) {
client := electrum.NewClient()
client := electrum.NewClient(true)

err := client.Connect(task.server)
if err != nil {
Expand All @@ -247,7 +247,7 @@ func testBatchSupport(task *surveyTask) (bool, error) {
// measureSpeed returns the amount of successful ListUnspentBatch calls in SPEED_TEST_DURATION
// seconds. It assumes batch support was verified beforehand.
func (s *Survey) measureSpeed(task *surveyTask) (int, error) {
client := electrum.NewClient()
client := electrum.NewClient(true)

err := client.Connect(task.server)
if err != nil {
Expand All @@ -273,7 +273,7 @@ func (s *Survey) measureSpeed(task *surveyTask) (int, error) {

// getPeers returns the list of peers from a server, or empty if it doesn't responds to the request
func getPeers(task *surveyTask) ([]string, error) {
client := electrum.NewClient()
client := electrum.NewClient(true)

err := client.Connect(task.server)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions sweeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ func (s *Sweeper) BuildSweepTx(utxos []*scanner.Utxo, fee int64) (*wire.MsgTx, e

func (s *Sweeper) BroadcastTx(tx *wire.MsgTx) error {
// Connect to an Electurm server using a fresh client and provider pair:
sp := electrum.NewServerProvider() // TODO create servers module, for provider and pool
client := electrum.NewClient()
sp := electrum.NewServerProvider(electrum.PublicServers) // TODO create servers module, for provider and pool
client := electrum.NewClient(true)

for !client.IsConnected() {
client.Connect(sp.NextServer())
Expand Down
2 changes: 1 addition & 1 deletion version.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ package main
// The OSS tool depends on this file with this content. If you need to change
// it, change the tool too.

const version = "2.2.3"
const version = "2.2.4"

0 comments on commit 72f9f69

Please sign in to comment.