From 3452da6ad112b8b0b083d68f44cb6cc89d2569ec Mon Sep 17 00:00:00 2001 From: ziggie Date: Mon, 19 Dec 2022 23:38:40 +0100 Subject: [PATCH 01/11] import descriptors in a bulk --- bus/wallet.go | 82 +++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/bus/wallet.go b/bus/wallet.go index b3c8d36..c9ae3d7 100644 --- a/bus/wallet.go +++ b/bus/wallet.go @@ -47,7 +47,7 @@ func (b *Bus) GetTransactionHex(hash *chainhash.Hash) (string, error) { return tx.Hex, nil } -//see https://developer.bitcoin.org/reference/rpc/importdescriptors.html for specs +// see https://developer.bitcoin.org/reference/rpc/importdescriptors.html for specs type ImportDesciptorRequest struct { Descriptor string `json:"desc"` //(string, required) Descriptor to import. Active bool `json:"active,omitempty"` //(boolean, optional, default=false) Set this descriptor to be the active descriptor for the corresponding output type/externality @@ -70,61 +70,67 @@ type ImportDescriptorResult struct { func ImportDescriptors(client *rpcclient.Client, descriptors []descriptor) error { - for _, descriptor := range descriptors { + // We are going to import all descriptors together which saves us a lot of time + + var requestDescriptors []ImportDesciptorRequest + var params []json.RawMessage - // only 1 request per descriptor - var requests = new([1]ImportDesciptorRequest) - var params []json.RawMessage + for _, descriptor := range descriptors { - requests[0] = ImportDesciptorRequest{ + requests := ImportDesciptorRequest{ Descriptor: descriptor.Value, + Active: true, Range: []int{0, descriptor.Depth}, Timestamp: descriptor.Age, } - myIn, mErr := json.Marshal(requests) + requestDescriptors = append(requestDescriptors, requests) - if mErr != nil { - log.Error(`mErr`, mErr) - return mErr - } + } - myInRaw := json.RawMessage(myIn) - params = append(params, myInRaw) + myIn, mErr := json.Marshal(requestDescriptors) - method := "importdescriptors" + if mErr != nil { + log.Error(`mErr`, mErr) + return mErr + } - result, err := client.RawRequest(method, params) + myInRaw := json.RawMessage(myIn) + params = append(params, myInRaw) - if err != nil { - log.Error(`err `, err) - return err - } + method := "importdescriptors" - var importDescriptorResult []ImportDescriptorResult - umerr := json.Unmarshal(result, &importDescriptorResult) + result, err := client.RawRequest(method, params) - if umerr != nil { - log.Error(`umerr `, umerr) - return umerr - } + if err != nil { + log.Error(`err `, err) + return err + } - var hasError bool + var importDescriptorResult []ImportDescriptorResult + umerr := json.Unmarshal(result, &importDescriptorResult) - fields := log.WithFields(log.Fields{ - "descriptor": descriptor.Value, - }) + if umerr != nil { + log.Error(`umerr `, umerr) + return umerr + } - if importDescriptorResult[0].Success == false { - fields.Error("ImportDescriptors - Failed to import descriptor" + " || " + importDescriptorResult[0].Error.Message + importDescriptorResult[0].Error.Error()) - hasError = true - } else { - fields.Debug("ImportDescriptors - Import descriptor successfully") - } + var hasError bool - if hasError { - return fmt.Errorf("ImportDescriptors - importdescriptor RPC failed") - } + fields := log.WithFields(log.Fields{ + "NumofDescriptor": len(requestDescriptors), + }) + + if !importDescriptorResult[0].Success { + + fields.Error("ImportDescriptors - Failed to import descriptor" + " || " + importDescriptorResult[0].Error.Error()) + hasError = true + } else { + fields.Debug("ImportDescriptors - Import descriptor successfully") + } + + if hasError { + return fmt.Errorf("ImportDescriptors - importdescriptor RPC failed") } return nil From b8cf485d482b0ce5f6dfa75c68f2d5fa24cf064d Mon Sep 17 00:00:00 2001 From: ziggie Date: Mon, 19 Dec 2022 23:41:03 +0100 Subject: [PATCH 02/11] check for new wallet loaded message --- bus/infrastructure.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bus/infrastructure.go b/bus/infrastructure.go index 1c77207..3edc473 100644 --- a/bus/infrastructure.go +++ b/bus/infrastructure.go @@ -37,8 +37,10 @@ const ( // bitcoind's wallet. walletName = "satstack" - errDuplicateWalletLoadMsg = "Duplicate -wallet filename specified." - errWalletAlreadyLoadedMsg = "Wallet file verification failed. Refusing to load database. Data file" + errDuplicateWalletLoadMsg = "Duplicate -wallet filename specified." + errWalletAlreadyLoadedMsgOld = "Wallet file verification failed. Refusing to load database. Data file" + // Cores Responds changes so adding the new one but keeping the old for backwards compatibility + errWalletAlreadyLoadedMsgNew = "Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database" ) // Bus represents a transport allowing access to Bitcoin RPC methods. @@ -303,7 +305,12 @@ func loadOrCreateWallet(client *rpcclient.Client) (bool, error) { return false, nil } - if rpcErr.Code == btcjson.ErrRPCWallet && strings.Contains(rpcErr.Message, errWalletAlreadyLoadedMsg) { + if rpcErr.Code == btcjson.ErrRPCWallet && strings.Contains(rpcErr.Message, errWalletAlreadyLoadedMsgOld) { + // wallet already loaded. Ignore the error and return. + return false, nil + } + + if rpcErr.Code == btcjson.ErrRPCWallet && strings.Contains(rpcErr.Message, errWalletAlreadyLoadedMsgNew) { // wallet already loaded. Ignore the error and return. return false, nil } From a9655be8ff6e86b925e3581d195c0ba66cfea906 Mon Sep 17 00:00:00 2001 From: ziggie Date: Mon, 19 Dec 2022 23:47:01 +0100 Subject: [PATCH 03/11] add skip-circulation-check --- bus/workers.go | 25 ++++++++++++++----------- cmd/cli/root.go | 9 ++++++--- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/bus/workers.go b/bus/workers.go index f64ae50..dfe14e2 100644 --- a/bus/workers.go +++ b/bus/workers.go @@ -204,7 +204,7 @@ func runTheNumbers(b *Bus) error { return nil } -func (b *Bus) Worker(config *config.Configuration) { +func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool) { importDone := make(chan bool) sendInterruptSignal := func() { @@ -239,19 +239,22 @@ func (b *Bus) Worker(config *config.Configuration) { return } - b.IsPendingScan = true + if !skipCirculationCheck { + b.IsPendingScan = true - if err := runTheNumbers(b); err != nil { - log.WithFields(log.Fields{ - "prefix": "worker", - "error": err, - }).Error("Failed while running the numbers") + if err := runTheNumbers(b); err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + "error": err, + }).Error("Failed while running the numbers") - sendInterruptSignal() - return - } + sendInterruptSignal() + return + } - b.IsPendingScan = false + b.IsPendingScan = false + + } if err := b.ImportAccounts(config.Accounts); err != nil { log.WithFields(log.Fields{ diff --git a/cmd/cli/root.go b/cmd/cli/root.go index 72ed273..fcbf794 100644 --- a/cmd/cli/root.go +++ b/cmd/cli/root.go @@ -21,6 +21,8 @@ import ( func init() { rootCmd.PersistentFlags().String("port", "20000", "Port") rootCmd.PersistentFlags().Bool("unload-wallet", false, "whether SatStack should unload wallet") + rootCmd.PersistentFlags().Bool("skip-circulation-check", false, "skip the circulation check") + } var rootCmd = &cobra.Command{ @@ -30,8 +32,9 @@ var rootCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { port, _ := cmd.Flags().GetString("port") unloadWallet, _ := cmd.Flags().GetBool("unload-wallet") + skipCirculationCheck, _ := cmd.Flags().GetBool("skip-circulation-check") - s := startup(unloadWallet) + s := startup(unloadWallet, skipCirculationCheck) if s == nil { return } @@ -93,7 +96,7 @@ func Execute() { } } -func startup(unloadWallet bool) *svc.Service { +func startup(unloadWallet bool, skipCirculationCheck bool) *svc.Service { // log.SetLevel(logrus.DebugLevel) @@ -147,7 +150,7 @@ func startup(unloadWallet bool) *svc.Service { fortunes.Fortune() - s.Bus.Worker(configuration) + s.Bus.Worker(configuration, skipCirculationCheck) return s } From 1b29dbe186d7ea29c3c5a4d726c0bf0753a975c7 Mon Sep 17 00:00:00 2001 From: ziggie Date: Tue, 20 Dec 2022 01:17:53 +0100 Subject: [PATCH 04/11] smaller bugfixes --- bus/wallet.go | 2 +- cmd/cli/root.go | 4 +++- magefile.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bus/wallet.go b/bus/wallet.go index c9ae3d7..5629344 100644 --- a/bus/wallet.go +++ b/bus/wallet.go @@ -118,7 +118,7 @@ func ImportDescriptors(client *rpcclient.Client, descriptors []descriptor) error var hasError bool fields := log.WithFields(log.Fields{ - "NumofDescriptor": len(requestDescriptors), + "NumofDescriptors": len(requestDescriptors), }) if !importDescriptorResult[0].Success { diff --git a/cmd/cli/root.go b/cmd/cli/root.go index fcbf794..ff6fc19 100644 --- a/cmd/cli/root.go +++ b/cmd/cli/root.go @@ -98,7 +98,9 @@ func Execute() { func startup(unloadWallet bool, skipCirculationCheck bool) *svc.Service { - // log.SetLevel(logrus.DebugLevel) + if version.Build == "development" { + log.SetLevel(log.DebugLevel) + } log.SetFormatter(&prefixed.TextFormatter{ TimestampFormat: "2006/01/02 - 15:04:05", diff --git a/magefile.go b/magefile.go index ab74d14..11def04 100644 --- a/magefile.go +++ b/magefile.go @@ -1,3 +1,4 @@ +//go:build mage // +build mage package main @@ -63,7 +64,7 @@ func flagEnv() map[string]string { } return map[string]string{ - "PACKAGE": "satstack", + "PACKAGE": "github.com/ledgerhq/satstack", "COMMIT_HASH": hash, "BUILD": build, } From b06d1c8ab62646569a0d38a80a692d5b84be6ed7 Mon Sep 17 00:00:00 2001 From: ziggie Date: Tue, 20 Dec 2022 19:07:01 +0100 Subject: [PATCH 05/11] add description for rpcauth and remove rpcuser/rpcpassword --- README.md | 67 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 8c24ba1..107fcd6 100644 --- a/README.md +++ b/README.md @@ -77,34 +77,58 @@ External: wpkh([b91fb6c1/84'/0'/3']xpub6D1gvTP...VeMLtH6/0/*) Internal: wpkh([b91fb6c1/84'/0'/3']xpub6D1gvTP...VeMLtH6/1/*) ``` -if you get an ``unsupported hash type ripemd160`` error, please see [this](https://stackoverflow.com/questions/72409563/unsupported-hash-type-ripemd160-with-hashlib-in-python) +if you get an `unsupported hash type ripemd160` error, please see [this](https://stackoverflow.com/questions/72409563/unsupported-hash-type-ripemd160-with-hashlib-in-python) ##### Create configuration file Create a config file **`lss.json`** in your home directory. You can use [this](https://github.com/ledgerhq/satstack/blob/master/lss.mainnet.json) sample config file as a template. -Add ```"torproxy": "socks5://127.0.0.1:9050",``` to connect to a Tor client running locally so that satstack can reach a full node behind Tor. -Replace the ```rpcurl``` with the .onion address of your node. +Add `"torproxy": "socks5://127.0.0.1:9050",` to connect to a Tor client running locally so that satstack can reach a full node behind Tor. +Replace the `rpcurl` with the .onion address of your node. ###### Optional account fields - **`depth`**: override the number of addresses to derive and import in the Bitcoin wallet. Defaults to `1000`. - **`birthday`**: set the earliest known creation date (`YYYY/MM/DD` format), for faster account import. -Defaults to `2013/09/10` ([BIP0039](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) proposal date). -Refer to the table below for a list of safe wallet birthdays to choose from. + Defaults to `2013/09/10` ([BIP0039](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) proposal date). + Refer to the table below for a list of safe wallet birthdays to choose from. - | Event | Date (YYYY/MM/DD) | - |-------|-------------------| - | BIP0039 proposal created | 2013/09/10 (default) | - | First ever BIP39 compatible Ledger device (Nano) shipped | 2014/11/24 | - | First ever Ledger Nano S shipped | 2016/07/28 | + | Event | Date (YYYY/MM/DD) | + | -------------------------------------------------------- | -------------------- | + | BIP0039 proposal created | 2013/09/10 (default) | + | First ever BIP39 compatible Ledger device (Nano) shipped | 2014/11/24 | + | First ever Ledger Nano S shipped | 2016/07/28 | ##### Launch Bitcoin full node Make sure you've read the [requirements](#requirements) first, and that your node is configured properly. Here's the recommended configuration for `bitcoin.conf`: +Don't use rpcuser/rpcpassword on your full node because they are insecure. Bitcoin-core changed to rpcauth. +Get the rpcauth.py script from the bitcoin repo and create a new user for satstack. + +``` +wget https://raw.githubusercontent.com/bitcoin/bitcoin/master/share/rpcauth/rpcauth.py + +python3 rpcauth.py satstack + +Example Output: +rpcauth=satstack:a14191e6892facf70686a397b126423$ddd6f7480817bd6f8083a2e07e24b93c4d74e667f3a001df26c5dd0ef5eafd0d +Your password: +VX3z87LBVc_X7NBLABLABLABLA +``` + +Copy the `rpcauth=` into your bitcoin.conf +Note down the password and use them in your lss.json. There you will use the credentials + +``` +In your lss.json: + +"rpcuser": "satstack", +"rpcpassword": "VX3z87LBVc_X7NBLABLABLABLA" +``` + ```config # Enable RPC server server=1 @@ -114,8 +138,9 @@ txindex=1 blockfilterindex=1 # Set RPC credentials -rpcuser= -rpcpassword= +# Example Auth, replace with your own. +# see https://bitcoin.stackexchange.com/questions/46782/rpc-cookie-authentication why we are not using normal rpcuser/password +rpcauth=satstack:a14191e6892facf70686a397b126423$ddd6f7480817bd6f8083a2e07e24b93c4d74e667f3a001df26c5dd0ef5eafd0d ``` Then launch `bitcoind` like this: @@ -154,18 +179,18 @@ $ EXPLORER=http://127.0.0.1:20000 ### Misc -If you get ```error=failed to load wallet: -4: Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?``` maybe this is because you have bitcoind windows opened, if this is the case, please try closing them and restart lss. +If you get `error=failed to load wallet: -4: Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?` maybe this is because you have bitcoind windows opened, if this is the case, please try closing them and restart lss. ### In the press -| Title | Source | -|:----------|:-------------:| -| 🇬🇧 [Personal sovereignty with Ledger SatStack](https://blog.ledger.com/satstack) | [blog.ledger.com](https://blog.ledger.com) | -| 🇫🇷 [Ledger SatStack: un pont entre Bitcoin Core et votre Ledger Wallet](https://bitcoin.fr/ledger-sat-stack-un-pont-entre-bitcoin-core-et-votre-ledger-wallet/) | [bitcoin.fr](https://bitcoin.fr) | -| 🇫🇷 [Votre propre coffre-fort à bitcoins… inviolable – Ledger annonce l’arrivée des full nodes Bitcoin](https://journalducoin.com/actualites/coffre-fort-bitcoins-inviolable-ledger-annonce-noeuds-complets-bitcoin) | [Journal du Coin](https://journalducoin.com) | -| 🇫🇷 [Il est désormais possible d’exécuter un full node Bitcoin sur Ledger Live](https://fr.beincrypto.com/technologie/5770/full-node-bitcoin-ledger-live) | [beincrypto.com](https://beincrypto.com) | -| 🇪🇸 [Ledger Live será compatible con nodos propios de Bitcoin](https://www.criptonoticias.com/tecnologia/ledger-live-sera-compatible-nodos-propios-bitcoin) | [CriptoNoticias](https://www.criptonoticias.com) | -| 🇬🇧 [Bitcoin Tech Talk #218: Curing Monetary Stockholm Syndrome](https://jimmysong.substack.com/p/curing-monetary-stockholm-syndrome) (mention) | [Jimmy Song](https://jimmysong.substack.com) | +| Title | Source | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------: | +| 🇬🇧 [Personal sovereignty with Ledger SatStack](https://blog.ledger.com/satstack) | [blog.ledger.com](https://blog.ledger.com) | +| 🇫🇷 [Ledger SatStack: un pont entre Bitcoin Core et votre Ledger Wallet](https://bitcoin.fr/ledger-sat-stack-un-pont-entre-bitcoin-core-et-votre-ledger-wallet/) | [bitcoin.fr](https://bitcoin.fr) | +| 🇫🇷 [Votre propre coffre-fort à bitcoins… inviolable – Ledger annonce l’arrivée des full nodes Bitcoin](https://journalducoin.com/actualites/coffre-fort-bitcoins-inviolable-ledger-annonce-noeuds-complets-bitcoin) | [Journal du Coin](https://journalducoin.com) | +| 🇫🇷 [Il est désormais possible d’exécuter un full node Bitcoin sur Ledger Live](https://fr.beincrypto.com/technologie/5770/full-node-bitcoin-ledger-live) | [beincrypto.com](https://beincrypto.com) | +| 🇪🇸 [Ledger Live será compatible con nodos propios de Bitcoin](https://www.criptonoticias.com/tecnologia/ledger-live-sera-compatible-nodos-propios-bitcoin) | [CriptoNoticias](https://www.criptonoticias.com) | +| 🇬🇧 [Bitcoin Tech Talk #218: Curing Monetary Stockholm Syndrome](https://jimmysong.substack.com/p/curing-monetary-stockholm-syndrome) (mention) | [Jimmy Song](https://jimmysong.substack.com) | ### Community From 81a25107e2a88268ca7c9d97cff0e4b3b5cd1762 Mon Sep 17 00:00:00 2001 From: ziggie Date: Tue, 20 Dec 2022 19:54:37 +0100 Subject: [PATCH 06/11] remember state of the wallet when restarting lss --- bus/chain.go | 5 ++ bus/infrastructure.go | 45 ++++++++++++- bus/wallet.go | 145 ++++++++++++++++++++++++++++++++++++++++++ bus/workers.go | 136 +++++++++++++++++++++++++++++++++++++-- cmd/cli/root.go | 32 +++++++++- config/loader.go | 71 ++++++++++++++++++++- config/models.go | 9 +++ config/writer..go | 57 +++++++++++++++++ 8 files changed, 485 insertions(+), 15 deletions(-) create mode 100644 config/writer..go diff --git a/bus/chain.go b/bus/chain.go index 352a739..64ee4e3 100644 --- a/bus/chain.go +++ b/bus/chain.go @@ -12,6 +12,11 @@ func (b *Bus) GetBestBlockHash() (*chainhash.Hash, error) { return b.mainClient.GetBestBlockHash() } +func (b *Bus) GetBlockCount() (int64, error) { + return b.mainClient.GetBlockCount() + +} + func (b *Bus) GetBlockHash(height int64) (*chainhash.Hash, error) { return b.mainClient.GetBlockHash(height) } diff --git a/bus/infrastructure.go b/bus/infrastructure.go index 3edc473..a4c656f 100644 --- a/bus/infrastructure.go +++ b/bus/infrastructure.go @@ -5,14 +5,18 @@ import ( "encoding/json" "fmt" "os" + "strconv" "strings" + "time" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/rpcclient" + "github.com/ledgerhq/satstack/config" "github.com/ledgerhq/satstack/utils" + "github.com/ledgerhq/satstack/version" "github.com/patrickmn/go-cache" log "github.com/sirupsen/logrus" ) @@ -43,6 +47,12 @@ const ( errWalletAlreadyLoadedMsgNew = "Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database" ) +var ( + // A new wallet needs to import the descriptors therefore + // we need this information when starting the import worker + isNewWallet bool +) + // Bus represents a transport allowing access to Bitcoin RPC methods. // // It maintains a pool of btcd rpcclient objects in a buffered channel to allow @@ -75,8 +85,8 @@ type Bus struct { Params *chaincfg.Params // IsPendingScan is a boolean field to indicate if satstack is currently - // waiting for descriptors to be scanned. One such example is when satstack - // is "running the numbers". + // waiting for descriptors to be scanned or other initial operations like "running the numbers" + // before the bridge can operate correctly // // This value can be exported for use by other packages to avoid making // explorer requests before satstack is able to serve them. @@ -158,7 +168,7 @@ func New(host string, user string, pass string, proxy string, noTLS bool, unload os.Exit(1) } - isNewWallet, err := loadOrCreateWallet(mainClient) + isNewWallet, err = loadOrCreateWallet(mainClient) if err != nil { return nil, err } @@ -456,3 +466,32 @@ func (b *Bus) UnloadWallet() { b.janitorClient.Shutdown() } + +func (b *Bus) DumpLatestRescanTime() error { + + currentHeight, err := b.GetBlockCount() + + if err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + }).Error("Error fetching blockheight: %s", err) + return err + + } + data := &config.ConfigurationRescan{ + TimeStamp: strconv.Itoa(int(time.Now().Unix())), + LastSyncTime: time.Now().Format(time.ANSIC), + LastBlock: currentHeight, + SatstackVersion: version.Version, + } + err = config.WriteRescanConf(data) + if err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + }).Error("Error savng last timestamp to file: %s", err) + return err + } + + return nil + +} diff --git a/bus/wallet.go b/bus/wallet.go index 5629344..4c182a8 100644 --- a/bus/wallet.go +++ b/bus/wallet.go @@ -2,6 +2,7 @@ package bus import ( "encoding/json" + "time" "fmt" @@ -47,6 +48,11 @@ func (b *Bus) GetTransactionHex(hash *chainhash.Hash) (string, error) { return tx.Hex, nil } +type RescanResult struct { + StartHeight uint32 `json:"start_height"` + StopHeight uint32 `json:"stop_height"` +} + // see https://developer.bitcoin.org/reference/rpc/importdescriptors.html for specs type ImportDesciptorRequest struct { Descriptor string `json:"desc"` //(string, required) Descriptor to import. @@ -178,3 +184,142 @@ func (b *Bus) GetTransaction(hash string) (*types.Transaction, error) { return tx, nil } + +func (b *Bus) checkWalletSyncStatus() error { + + client, err := b.ClientFactory() + if err != nil { + return err + } + + defer client.Shutdown() + + log.Debug("checkWalletSyncStatus") + + walletInfo, err := client.GetWalletInfo() + if err != nil { + return err + } + + switch v := walletInfo.Scanning.Value.(type) { + case btcjson.ScanProgress: + log.WithFields(log.Fields{ + "progress": fmt.Sprintf("%.2f%%", v.Progress*100), + "duration": utils.HumanizeDuration( + time.Duration(v.Duration) * time.Second), + }).Debug("satsstack wallet is syncing") + b.IsPendingScan = true + default: + // Not scanning currently, or scan is complete. + log.Debug("wallet is not syncing") + b.IsPendingScan = false + } + + return nil +} + +// Triggers the bitcoind api to rescan the wallet, in case the wallet +// satstack already existed +func (b *Bus) rescanWallet(startHeight int64, endHeight int64) error { + + client, err := b.ClientFactory() + if err != nil { + return err + } + + defer client.Shutdown() + + log.WithFields(log.Fields{ + "prefix": "RescanWallet", + }).Infof("Rescanning Wallet start_height: %d, end_height %d", startHeight, endHeight) + + b.IsPendingScan = true + + var params []json.RawMessage + var rescanResult RescanResult + + myIn, mErr := json.Marshal(startHeight) + + if mErr != nil { + log.Error(`mErr`, mErr) + return mErr + } + + myInRaw := json.RawMessage(myIn) + params = append(params, myInRaw) + + myIn, mErr = json.Marshal(uint32(endHeight)) + + if mErr != nil { + log.Error(`mErr`, mErr) + return mErr + } + + myInRaw = json.RawMessage(myIn) + params = append(params, myInRaw) + + result, err := client.RawRequest("rescanblockchain", params) + + if err != nil { + log.WithFields(log.Fields{ + "prefix": "RescanWallet", + "error": err, + }).Error("Failed to Rescan Blockchain") + + return err + } + + umerr := json.Unmarshal(result, &rescanResult) + + if umerr != nil { + log.Error(`umerr`, umerr) + return umerr + } + + log.WithFields(log.Fields{ + "prefix": "RescanWallet", + }).Infof("Rescan wallet was successful: start_height: %d, stop_height: %d", rescanResult.StartHeight, rescanResult.StopHeight) + + b.IsPendingScan = false + + return nil + +} + +func (b *Bus) AbortRescan() error { + + var params []json.RawMessage + var abortRescan bool + + client, err := b.ClientFactory() + if err != nil { + return err + } + + defer client.Shutdown() + + result, err := client.RawRequest("abortrescan", params) + + if err != nil { + log.WithFields(log.Fields{ + "prefix": "AbortRescan", + "error": err, + }).Error("Failed to abort wallet rescan") + + return err + } + + umerr := json.Unmarshal(result, &abortRescan) + + if umerr != nil { + log.Error(`umerr`, umerr) + return umerr + } + + log.WithFields(log.Fields{ + "prefix": "AbortRescan", + }).Infof("Abort rescan successful: %t", abortRescan) + + return nil + +} diff --git a/bus/workers.go b/bus/workers.go index dfe14e2..af10a5e 100644 --- a/bus/workers.go +++ b/bus/workers.go @@ -121,6 +121,19 @@ func (b *Bus) ImportAccounts(accounts []config.Account) error { return ImportDescriptors(client, descriptorsToImport) } +func getPreviousRescanBlock() (int64, error) { + + configRescan, err := config.LoadRescanConf() + + if err != nil { + log.Errorf("loading rescan config: %s", err) + return -1, err + } + + return configRescan.LastBlock, nil + +} + // descriptors returns canonical descriptors from the account configuration. func descriptors(client *rpcclient.Client, account config.Account) ([]descriptor, error) { var ret []descriptor @@ -204,7 +217,8 @@ func runTheNumbers(b *Bus) error { return nil } -func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool) { +func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool, + forceImportDesc bool) { importDone := make(chan bool) sendInterruptSignal := func() { @@ -256,14 +270,124 @@ func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool) { } - if err := b.ImportAccounts(config.Accounts); err != nil { + // We allow the user to force an import of all descriptors + // which will trigger a rescan automatically using the timestamp + // in the importDescriptorRequest + if forceImportDesc || isNewWallet { + + // updates status of the wallet + // if wallet is syncing we do not want + // to kill the syncing otherwise the importDescriptor call + // will fail + if forceImportDesc { + err := b.checkWalletSyncStatus() + + if err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + "error": err, + }).Error("failed to check wallet status") + + sendInterruptSignal() + return + + } + + if b.IsPendingScan { + // Interrupt Scan + err = b.AbortRescan() + if err != nil { + sendInterruptSignal() + return + } + } + } + + // The ImportDescriptor call is a blocking operation + // and will automatically trigger a wallet scan + b.IsPendingScan = true + + if err := b.ImportAccounts(config.Accounts); err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + "error": err, + }).Error("Failed while importing descriptors") + + sendInterruptSignal() + return + } + + b.IsPendingScan = false + + } else { + // wallet is loaded + err := b.checkWalletSyncStatus() + if err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + "error": err, + }).Error("failed to check wallet status") + + sendInterruptSignal() + return + } + + if b.IsPendingScan { + + for { + err := b.checkWalletSyncStatus() + if err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + "error": err, + }).Error("failed to check wallet status") + + sendInterruptSignal() + return + } + + if !b.IsPendingScan { + log.WithFields(log.Fields{ + "prefix": "worker", + }).Info("Wallet Rescan finished") + break + } + time.Sleep(1 * time.Second) + } + + } else { + // wallet is not scanning but we need to + // catch up with history so we need to rescan the + // wallet from the last time satstack was shut down + + startHeight, err := getPreviousRescanBlock() + + if err != nil { + // no rescanning necessary + log.Info("In case you run satstack for the first this error can be ignored: ", err) + return + } + + endHeight, _ := b.GetBlockCount() + + // Begin Starting rescan, this is a blocking call + err = b.rescanWallet(startHeight, endHeight) + if err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + "error": err, + }).Error("Failed to rescan blocks") + sendInterruptSignal() + return + } + } + } + err := b.DumpLatestRescanTime() + if err != nil { log.WithFields(log.Fields{ "prefix": "worker", "error": err, - }).Error("Failed while importing descriptors") - - sendInterruptSignal() - return + }).Error("Failed to dump latest block into") } importDone <- true diff --git a/cmd/cli/root.go b/cmd/cli/root.go index ff6fc19..10ca84d 100644 --- a/cmd/cli/root.go +++ b/cmd/cli/root.go @@ -22,6 +22,7 @@ func init() { rootCmd.PersistentFlags().String("port", "20000", "Port") rootCmd.PersistentFlags().Bool("unload-wallet", false, "whether SatStack should unload wallet") rootCmd.PersistentFlags().Bool("skip-circulation-check", false, "skip the circulation check") + rootCmd.PersistentFlags().Bool("force-importdescriptors", false, "this will force importing descriptors although the wallet does already exist") } @@ -33,8 +34,9 @@ var rootCmd = &cobra.Command{ port, _ := cmd.Flags().GetString("port") unloadWallet, _ := cmd.Flags().GetBool("unload-wallet") skipCirculationCheck, _ := cmd.Flags().GetBool("skip-circulation-check") + forceImportDesc, _ := cmd.Flags().GetBool("force-importdescriptors") - s := startup(unloadWallet, skipCirculationCheck) + s := startup(unloadWallet, skipCirculationCheck, forceImportDesc) if s == nil { return } @@ -65,6 +67,30 @@ var rootCmd = &cobra.Command{ log.Info("Shutdown server: in progress") { + + // In case we are scanning the wallet, we have to abort the wallet + // because unloading the wallet while scanning will result in a timeout + // and a non recoverable state. This will be fixed by + // https://github.com/bitcoin/bitcoin/pull/26618 + + if s.Bus.IsPendingScan { + + err := s.Bus.AbortRescan() + if err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to abort rescan") + } + } else { + err := s.Bus.DumpLatestRescanTime() + if err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + "error": err, + }).Error("Failed to dump latest block into file") + } + } + // Scoped block to disconnect all connections, and stop all goroutines. // If not successful within 5s, drop a nuclear bomb and fail with a // FATAL error. @@ -96,7 +122,7 @@ func Execute() { } } -func startup(unloadWallet bool, skipCirculationCheck bool) *svc.Service { +func startup(unloadWallet bool, skipCirculationCheck bool, forceImportDesc bool) *svc.Service { if version.Build == "development" { log.SetLevel(log.DebugLevel) @@ -152,7 +178,7 @@ func startup(unloadWallet bool, skipCirculationCheck bool) *svc.Service { fortunes.Fortune() - s.Bus.Worker(configuration, skipCirculationCheck) + s.Bus.Worker(configuration, skipCirculationCheck, forceImportDesc) return s } diff --git a/config/loader.go b/config/loader.go index ea1b823..eea64ff 100644 --- a/config/loader.go +++ b/config/loader.go @@ -16,9 +16,9 @@ import ( // // It searches for the config file in a standard set of directories, in the // following order: -// 1. Ledger Live user data folder. -// 2. Current directory. -// 3. User's home directory. +// 1. Ledger Live user data folder. +// 2. Current directory. +// 3. User's home directory. // // The filename is always expected to be lss.json. func Load() (*Configuration, error) { @@ -53,6 +53,34 @@ func Load() (*Configuration, error) { return configuration, nil } +func LoadRescanConf() (*ConfigurationRescan, error) { + paths, err := configRescanLookupPaths() + if err != nil { + return nil, err + } + + var configPath string + for _, maybePath := range paths { + if fileExists(maybePath) { + configPath = maybePath + break + } + } + + if configPath == "" { + return nil, ErrConfigFileNotFound + } + + log.WithField("path", configPath).Info("Rescan Config file detected") + + configuration, err := loadFromPathRescan(configPath) + if err != nil { + return nil, fmt.Errorf("%s: %w", ErrMalformed, err) + } + + return configuration, nil +} + // fileExists checks if a file exists and is not a directory before we // try using it to prevent further errors. func fileExists(filename string) bool { @@ -87,6 +115,30 @@ func loadFromPath(path string) (*Configuration, error) { return configuration, nil } +func loadFromPathRescan(path string) (*ConfigurationRescan, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + + defer func() { + err := file.Close() + if err != nil { + panic(err) + } + }() + + decoder := json.NewDecoder(file) + + configuration := &ConfigurationRescan{} + err = decoder.Decode(configuration) + if err != nil { + return nil, err + } + + return configuration, nil +} + func configLookupPaths() ([]string, error) { home, err := homedir.Dir() if err != nil { @@ -100,6 +152,19 @@ func configLookupPaths() ([]string, error) { }, nil } +func configRescanLookupPaths() ([]string, error) { + home, err := homedir.Dir() + if err != nil { + return nil, fmt.Errorf("%s: %w", ErrHomeNotFound, err) + } + + return []string{ + path.Join(liveUserDataFolder(home), "lss_rescan.json"), + "lss_rescan.json", + path.Join(home, "lss_rescan.json"), + }, nil +} + func liveUserDataFolder(home string) string { switch runtime.GOOS { case "linux": diff --git a/config/models.go b/config/models.go index 3fa42c2..9c471fc 100644 --- a/config/models.go +++ b/config/models.go @@ -28,6 +28,15 @@ type Configuration struct { Accounts []Account `json:"accounts"` } +// Type for saving the Rescan time to avoid scanning the wallet +// always from the beginning +type ConfigurationRescan struct { + LastSyncTime string `json:"last_synctime"` + TimeStamp string `json:"timestamp"` + LastBlock int64 `json:"last_block"` + SatstackVersion string `json:"satstack_version"` +} + type date struct { time.Time } diff --git a/config/writer..go b/config/writer..go new file mode 100644 index 0000000..65b6995 --- /dev/null +++ b/config/writer..go @@ -0,0 +1,57 @@ +package config + +import ( + "encoding/json" + "os" + + log "github.com/sirupsen/logrus" +) + +func WriteRescanConf(data *ConfigurationRescan) error { + paths, err := configRescanLookupPaths() + if err != nil { + return err + } + + var configPath string + for _, maybePath := range paths { + if fileExists(maybePath) { + configPath = maybePath + break + } + } + + if configPath == "" { + // if the file does not exist, save to home dir + // check where the lss.json lies and take the same path + lssPath, err := configRescanLookupPaths() + if err != nil { + return err + } + + for index, maybePath := range lssPath { + if fileExists(maybePath) { + configPath = paths[index] + break + } + } + } + // This should never happen, in case we have no lss.json + // we should fail before + if configPath == "" { + return ErrConfigFileNotFound + } + + // Writing to file + + file, _ := json.MarshalIndent(*data, "", " ") + ferr := os.WriteFile(configPath, file, 0644) + if ferr != nil { + log.Error("Error savng last timestamp to file %s: %s", configPath, ferr) + return err + } + + log.WithField("path", configPath).Info("RescanConfigFile successfully saved") + + return nil +} From c8e2f6f61f5f286c19205ca271c365dcab5575a0 Mon Sep 17 00:00:00 2001 From: ziggie Date: Thu, 22 Dec 2022 18:52:44 +0100 Subject: [PATCH 07/11] bumps version to 0.17 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index c937064..942b2c1 100644 --- a/version/version.go +++ b/version/version.go @@ -9,7 +9,7 @@ import ( var GitCommit string // Version returns the main version number that is being run at the moment. -const Version = "v0.16.1" +const Version = "v0.17" // Build indicates whether the build was a development or a production build. var Build string From 55f3690dfa62f063fc26264993f8cd3f8001bd47 Mon Sep 17 00:00:00 2001 From: ziggie Date: Thu, 22 Dec 2022 23:48:25 +0100 Subject: [PATCH 08/11] don't unload wallet if we are still scanning when shutting done --- bus/infrastructure.go | 6 +++++- bus/wallet.go | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bus/infrastructure.go b/bus/infrastructure.go index a4c656f..398a8b4 100644 --- a/bus/infrastructure.go +++ b/bus/infrastructure.go @@ -218,7 +218,11 @@ func (b *Bus) Close(ctx context.Context) { b.mainClient.Shutdown() b.secondaryClient.Shutdown() - b.UnloadWallet() + // Only unload wallet if we are not in a pending scan + // otherwise the nuclear timeout corrupts the wallet state + if !b.IsPendingScan { + b.UnloadWallet() + } done <- true }() diff --git a/bus/wallet.go b/bus/wallet.go index 4c182a8..8150c14 100644 --- a/bus/wallet.go +++ b/bus/wallet.go @@ -320,6 +320,8 @@ func (b *Bus) AbortRescan() error { "prefix": "AbortRescan", }).Infof("Abort rescan successful: %t", abortRescan) + b.IsPendingScan = false + return nil } From fdee767a21cdd89e0071883830372c727c92b4a1 Mon Sep 17 00:00:00 2001 From: ziggie Date: Mon, 9 Jan 2023 21:10:38 +0100 Subject: [PATCH 09/11] bugfix when intial wallet configuartion --- bus/infrastructure.go | 2 +- bus/workers.go | 79 +++++++++++++++---------------------------- config/loader.go | 2 ++ config/writer..go | 5 ++- go.mod | 2 +- go.sum | 2 ++ httpd/svc/explorer.go | 1 + 7 files changed, 39 insertions(+), 54 deletions(-) diff --git a/bus/infrastructure.go b/bus/infrastructure.go index 398a8b4..68bb1cb 100644 --- a/bus/infrastructure.go +++ b/bus/infrastructure.go @@ -492,7 +492,7 @@ func (b *Bus) DumpLatestRescanTime() error { if err != nil { log.WithFields(log.Fields{ "prefix": "worker", - }).Error("Error savng last timestamp to file: %s", err) + }).Errorf("Error saving last timestamp to file: %s", err) return err } diff --git a/bus/workers.go b/bus/workers.go index af10a5e..e61c6fe 100644 --- a/bus/workers.go +++ b/bus/workers.go @@ -126,7 +126,6 @@ func getPreviousRescanBlock() (int64, error) { configRescan, err := config.LoadRescanConf() if err != nil { - log.Errorf("loading rescan config: %s", err) return -1, err } @@ -270,15 +269,20 @@ func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool, } + // We check whether the lss_rescan.json exists + startHeight, err := getPreviousRescanBlock() + if err != nil { + log.Debugf("No lss_rescan.json file found %s", err) + } + // We allow the user to force an import of all descriptors // which will trigger a rescan automatically using the timestamp // in the importDescriptorRequest - if forceImportDesc || isNewWallet { + if forceImportDesc || isNewWallet || startHeight == -1 { - // updates status of the wallet - // if wallet is syncing we do not want - // to kill the syncing otherwise the importDescriptor call - // will fail + // Check whether the wallet is syncing in the background + // if so, the sync is aborted so that we can import the + // descriptors in the next step if forceImportDesc { err := b.checkWalletSyncStatus() @@ -320,7 +324,7 @@ func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool, b.IsPendingScan = false } else { - // wallet is loaded + // wallet is loaded and exists in the backend err := b.checkWalletSyncStatus() if err != nil { log.WithFields(log.Fields{ @@ -333,56 +337,29 @@ func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool, } if b.IsPendingScan { - - for { - err := b.checkWalletSyncStatus() - if err != nil { - log.WithFields(log.Fields{ - "prefix": "worker", - "error": err, - }).Error("failed to check wallet status") - - sendInterruptSignal() - return - } - - if !b.IsPendingScan { - log.WithFields(log.Fields{ - "prefix": "worker", - }).Info("Wallet Rescan finished") - break - } - time.Sleep(1 * time.Second) - } - - } else { - // wallet is not scanning but we need to - // catch up with history so we need to rescan the - // wallet from the last time satstack was shut down - - startHeight, err := getPreviousRescanBlock() - + err := b.AbortRescan() if err != nil { - // no rescanning necessary - log.Info("In case you run satstack for the first this error can be ignored: ", err) - return + log.WithFields(log.Fields{ + "error": err, + }).Error("Failed to abort rescan") } + } - endHeight, _ := b.GetBlockCount() + endHeight, _ := b.GetBlockCount() - // Begin Starting rescan, this is a blocking call - err = b.rescanWallet(startHeight, endHeight) - if err != nil { - log.WithFields(log.Fields{ - "prefix": "worker", - "error": err, - }).Error("Failed to rescan blocks") - sendInterruptSignal() - return - } + // Begin Starting rescan, this is a blocking call + err = b.rescanWallet(startHeight, endHeight) + if err != nil { + log.WithFields(log.Fields{ + "prefix": "worker", + "error": err, + }).Error("Failed to rescan blocks") + sendInterruptSignal() + return } } - err := b.DumpLatestRescanTime() + + err = b.DumpLatestRescanTime() if err != nil { log.WithFields(log.Fields{ "prefix": "worker", diff --git a/config/loader.go b/config/loader.go index eea64ff..6139483 100644 --- a/config/loader.go +++ b/config/loader.go @@ -148,6 +148,7 @@ func configLookupPaths() ([]string, error) { return []string{ path.Join(liveUserDataFolder(home), "lss.json"), "lss.json", + path.Join(home, ".satstack", "lss.json"), path.Join(home, "lss.json"), }, nil } @@ -161,6 +162,7 @@ func configRescanLookupPaths() ([]string, error) { return []string{ path.Join(liveUserDataFolder(home), "lss_rescan.json"), "lss_rescan.json", + path.Join(home, ".satstack", "lss_rescan.json"), path.Join(home, "lss_rescan.json"), }, nil } diff --git a/config/writer..go b/config/writer..go index 65b6995..3978998 100644 --- a/config/writer..go +++ b/config/writer..go @@ -7,6 +7,9 @@ import ( log "github.com/sirupsen/logrus" ) +// WriteRescanConf writes the rescan information into a file +// when it does not exist it saves it to the same location +// where the lss.json is stored func WriteRescanConf(data *ConfigurationRescan) error { paths, err := configRescanLookupPaths() if err != nil { @@ -24,7 +27,7 @@ func WriteRescanConf(data *ConfigurationRescan) error { if configPath == "" { // if the file does not exist, save to home dir // check where the lss.json lies and take the same path - lssPath, err := configRescanLookupPaths() + lssPath, err := configLookupPaths() if err != nil { return err } diff --git a/go.mod b/go.mod index 33feadb..b5cb839 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.2 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 github.com/gin-gonic/gin v1.8.1 - github.com/magefile/mage v1.13.0 + github.com/magefile/mage v1.14.0 github.com/mattn/go-runewidth v0.0.13 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-wordwrap v1.0.1 diff --git a/go.sum b/go.sum index 3b58cff..dc44134 100644 --- a/go.sum +++ b/go.sum @@ -95,6 +95,8 @@ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/magefile/mage v1.13.0 h1:XtLJl8bcCM7EFoO8FyH8XK3t7G5hQAeK+i4tq+veT9M= github.com/magefile/mage v1.13.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= +github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= diff --git a/httpd/svc/explorer.go b/httpd/svc/explorer.go index 5f0d9a0..15cbe49 100644 --- a/httpd/svc/explorer.go +++ b/httpd/svc/explorer.go @@ -44,6 +44,7 @@ func (s *Service) GetStatus() *bus.ExplorerStatus { } // Case 1: satstack is running the numbers. + // or rescanning the wallet if s.Bus.IsPendingScan { status.Status = bus.PendingScan return &status From 3a946cfaaed0733179f6675e57d4c0757e0d1d24 Mon Sep 17 00:00:00 2001 From: ziggie Date: Tue, 10 Jan 2023 10:16:11 +0100 Subject: [PATCH 10/11] update README --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 107fcd6..ad1b555 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,17 @@ page (Linux, Windows, MacOS). Extract the tarball, and launch it as: ```sh ./lss ``` +There are some cmd handle which can be useful when setting up the setup the first time you can list them with + +`./lss -h` or `./lss --help` + +When setting up a new wallet, the wallet is synced form the birthday date or your custom date set in `lss.json` +When the initial sync sucessfully completes, satstack saves a file called `lss_rescan.json` at the exact location +where the lss.json is stored. This file includes the latest blockheight your wallet was synced to, this allows +satstack on every restart to not rescan the whole wallet again but only rescan the difference between the current +blockheight. You can also change the latest blockheight manually in the file which helps you to set the rescan delta +manually. This file is only created when an initial wallet sync was successful. Removing the file will lead satstack +to rescan the complete wallet again when starting up. If you want to build `lss` yourself, just do the following: From d1ac916e4ba4b0a5abee95f854b771720cf6a8ef Mon Sep 17 00:00:00 2001 From: ziggie Date: Wed, 11 Jan 2023 11:01:58 +0100 Subject: [PATCH 11/11] update README && make circulation check optional --- README.md | 20 ++++++++++++++++++-- bus/workers.go | 6 +++--- cmd/cli/root.go | 13 +++++++------ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ad1b555..5de5fc0 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,23 @@ Replace the `rpcurl` with the .onion address of your node. Make sure you've read the [requirements](#requirements) first, and that your node is configured properly. Here's the recommended configuration for `bitcoin.conf`: -Don't use rpcuser/rpcpassword on your full node because they are insecure. Bitcoin-core changed to rpcauth. +It is not recommended to use rpcuser/rpcpassword in the bitcoin.conf of your full node use rpcauth instead. +If you still want to use it make sure the following settings are in your bitcoin.conf file: + +``` +# Enable RPC server +server=1 + +# Enable indexes +txindex=1 +blockfilterindex=1 + +# Set RPC credentials +rpcuser= +rpcpassword= +``` + +If you want to use the newest security standard recommended by the core-devs then read the following paragraph. Get the rpcauth.py script from the bitcoin repo and create a new user for satstack. ``` @@ -157,7 +173,7 @@ page (Linux, Windows, MacOS). Extract the tarball, and launch it as: ```sh ./lss ``` -There are some cmd handle which can be useful when setting up the setup the first time you can list them with +There are some cmd handles which can be useful when configuring the setup the first time. List them with `./lss -h` or `./lss --help` diff --git a/bus/workers.go b/bus/workers.go index e61c6fe..d8a9056 100644 --- a/bus/workers.go +++ b/bus/workers.go @@ -216,7 +216,7 @@ func runTheNumbers(b *Bus) error { return nil } -func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool, +func (b *Bus) Worker(config *config.Configuration, circulationCheck bool, forceImportDesc bool) { importDone := make(chan bool) @@ -252,7 +252,7 @@ func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool, return } - if !skipCirculationCheck { + if circulationCheck { b.IsPendingScan = true if err := runTheNumbers(b); err != nil { @@ -272,7 +272,7 @@ func (b *Bus) Worker(config *config.Configuration, skipCirculationCheck bool, // We check whether the lss_rescan.json exists startHeight, err := getPreviousRescanBlock() if err != nil { - log.Debugf("No lss_rescan.json file found %s", err) + log.Debugf("No lss_rescan.json was found: %s", err) } // We allow the user to force an import of all descriptors diff --git a/cmd/cli/root.go b/cmd/cli/root.go index 10ca84d..abc9437 100644 --- a/cmd/cli/root.go +++ b/cmd/cli/root.go @@ -21,8 +21,9 @@ import ( func init() { rootCmd.PersistentFlags().String("port", "20000", "Port") rootCmd.PersistentFlags().Bool("unload-wallet", false, "whether SatStack should unload wallet") - rootCmd.PersistentFlags().Bool("skip-circulation-check", false, "skip the circulation check") - rootCmd.PersistentFlags().Bool("force-importdescriptors", false, "this will force importing descriptors although the wallet does already exist") + rootCmd.PersistentFlags().Bool("circulation-check", false, "performs inflation checks against the connected full node") + rootCmd.PersistentFlags().Bool("force-importdescriptors", false, "this will force importing descriptors although the wallet does already exist "+ + "which will force the wallet to rescan from the brithday date") } @@ -33,10 +34,10 @@ var rootCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { port, _ := cmd.Flags().GetString("port") unloadWallet, _ := cmd.Flags().GetBool("unload-wallet") - skipCirculationCheck, _ := cmd.Flags().GetBool("skip-circulation-check") + circulationCheck, _ := cmd.Flags().GetBool("circulation-check") forceImportDesc, _ := cmd.Flags().GetBool("force-importdescriptors") - s := startup(unloadWallet, skipCirculationCheck, forceImportDesc) + s := startup(unloadWallet, circulationCheck, forceImportDesc) if s == nil { return } @@ -122,7 +123,7 @@ func Execute() { } } -func startup(unloadWallet bool, skipCirculationCheck bool, forceImportDesc bool) *svc.Service { +func startup(unloadWallet bool, circulationCheck bool, forceImportDesc bool) *svc.Service { if version.Build == "development" { log.SetLevel(log.DebugLevel) @@ -178,7 +179,7 @@ func startup(unloadWallet bool, skipCirculationCheck bool, forceImportDesc bool) fortunes.Fortune() - s.Bus.Worker(configuration, skipCirculationCheck, forceImportDesc) + s.Bus.Worker(configuration, circulationCheck, forceImportDesc) return s }