Welcome to ElectrumSV’s documentation!

ElectrumSV is a wallet application for Bitcoin SV, a peer to peer form of electronic cash. As a wallet application it allows you to track, receive and spend bitcoin whenever you need to. But that’s just the basics, as it manages and secures your keys it also helps you to do many other things.

Important

ElectrumSV can only be downloaded from electrumsv.io.

Getting started

Before you can send and receive payments, you need to first create a wallet, and then create at least one account within it.

How do you know you have the official software and not malware?

Every person who had their coins stolen and was interested in investigating, identified that they had not downloaded from our official web site, and had instead obtained malware from some other fake site. Many swore they downloaded from the official site until their verified their download and found it to be malware. Read more about verifying your download.

How do you create a wallet?

Your wallet is a standalone container for all your bitcoin-related data. You should be able to create as many accounts as you need within it, each account containing separated funds much like a bank account. Read more about creating a wallet.

How do you create an account?

Each account in your wallet is much like a bank account, with the funds in each separated from the others. Read more about creating a new account.

How do you receive a payment from someone else?

Each account has the ability to provide countless unique and private receiving addresses and by giving a different one of these out to each person who will send you coins, allows you to receive funds from them. Read more about receiving a payment.

How do you make a payment to someone else?

By obtaining an address from another person, if you have coins in one of your accounts, you should be able to send some or all of those coins to that address. Read more about making a payment.

How do you scan the blockchain?

Whether you have restored the wallet, or you are an advanced user and you have given out a payment destination ElectrumSV does not know about, it is necessary to be able to find payments related to your wallet that exist on the blockchain. Read more about making a payment.

Verifying your download

Probably a dozen people have reported having their coins stolen, and any who were willing to investigate found they had downloaded a malware version of ElectrumSV and not an official download. More than one asserted that they had downloaded from our web site, but what they meant was that they had downloaded from a fake web site that had stolen our design.

Downloading an executable from a web site and running it is risky, and what you are putting your trust in, is that because you download from our official web site you are getting an executable you can safely run. Despite this, well meaning people have downloaded from fake versions of our web site, and paid the price for it.

It is in your best interests to verify your download is the official one. The goal of this page is to try and show you how to do that.

What are you verifying?

You will be checking the checksum (also known as a hash) of the file you downloaded. This is a standard algorithm that you can get lots of different software for, which will give you a series of letters and numbers that represent the uniqueness of your file. The algorithm we use for ElectrumSV is called SHA256 and we provide an official checksum for each file we make available. You will be comparing that official checksum to the one generated for your file. If it is the same, you should have the official version of that file. If it is different, you have downloaded malware instead.

The official checksums

We do not provide the checksums on the official web site where you find our download links, because this allows any attacker who manages to compromise the web site, to also replace the official checksums. Additionally, if there is a fake web site that offers both download links and checksums you should know something is fishy.

The official checksums are available from Github, where our open source code is located. You do not need to compare against the illustrative screenshot below, just click on the Github link and view them there.

The list SHA256 hashes for the official downloads.

The list SHA256 hashes for the official downloads.

Verifying your download

There is no easy way to check a download. Some level of technical competence is useful, although if you do not consider yourself technically competent and can follow instructions you should still be able to do it. Others have managed to do it, and as we get these instructions into a more approachable state over time, you should be able to as well.

Find your operating system below, and check out the options listed for it. Some of them may be better than others, but some assurance that your download is legitimate is better than nothing.

Windows

Several methods of verifying your download on Windows are provided below. Any one should be good enough, but if you are a user who primarily uses a web browser you may need to learn to use the explorer or console.

Using the digital signatures

Thanks to the kindness of the Bitcoin Association, we now have the ability to sign our Windows executables from version 1.3.12 and above. In theory the presence of our signature on the executable you downloaded should be just as reliable as checking the checksum. You can check if the executable you downloaded has our signature, and if it is present you can assume that the file should be legitimate. Your first step is to find the executable you downloaded with the Windows explorer. You can open the Windows explorer with the windows and e key, then locate the directory your executable is located in.

Windows explorer.

Windows explorer.

Right click on the file, and select Properties. This should open the properties window for the file, where you should select the Digital Signatures tab to see the signature.

The digital signature.

The digital signature.

From there click on Details and then View Certificate. You should see a certificate with the following information for the given version.

1.3.12 and above

The certificate should be issued to Bitcoin Association for BSV, be issued by COMODO RSA Extended Validation Code Signing CA and as of the time of writing be valid from 10/11/2020 to 11/11/2022.

The digital certificate.

The certificate the file was signed with.

Using certutil

certutil is already present in your Windows installation already. However, it requires opening a command prompt to run it, which might be something beyond some users. Press the Windows key and the s key at the same time, this will open the Windows searchy thing and there you can type cmd and then press the enter key to open a command prompt.

Opening a command prompt

Opening a command prompt.

Then you need to change the directory until you are in the same directory as the file you wish to get a checksum for. The cd command is used for this. Then you can use the certutil command to generate a SHA 256 checksum for that file. The syntax is certutil --hashfile <filename> SHA256, but remember you need to replace <filename> with the actual file name. You can see an illustration of this in the image below.

The certutil checksum result

The certutil checksum result.

If you find the ElectrumSV-1.3.12.exe entry in the linked Github list, you can see it matches the certutil checksum result. The case of the letters does not matter, both lower case and upper case are equivalent. If you get a different result, and the command complains that it cannot find the file, then the file is not in the current directory. You need to use the cd command to change the current directory as mentioned above.

Using 7-Zip

This requires that you download the 7-Zip installer. Any of the non-standalone executables from the 7-Zip web site, should be fine. Download one and install it. Once it is installed, you should have a handy context menu available that can give you the SHA 256 checksum for your file. Simply select your file, open the context menu and generate the checksum. Do not reflect on the fact that no-one in their life ever wanted to “Share with Skype” and that they put it up the top before all the useful stuff.

The 7-Zip context menu

The 7-Zip context menu.

In this case, we selected the SHA-256 menu option for the ElectrumSV-1.3.12.exe file and the following image shows the resulting checksum.

The 7-Zip checksum result

The 7-Zip checksum result.

If you find the ElectrumSV-1.3.12.exe entry in the linked Github list, you can see it matches the 7-zip checksum result. The case of the letters does not matter, both lower case and upper case are equivalent.

MacOS

The following approaches require the user to deal with the terminal. If you are unable to work out how to do this, remember you can always file a support request on the official ElectrumSV issue tracker.

shasum

This approach requires no application installation, but it does involve you being willing to use the terminal application. If you do not know how to locate this, start by opening the launchpad application using it’s rocket icon in the dock.

Open the launchpad application search.

Open the launchpad application search.

You should see the screen shown below. Enter terminal and it should show you one matching application which you should open.

Search for the 'terminal' application.

Search for the ‘terminal’ application.

Work out what directory the terminal is looking at, and change it using the cd command. In the case shown below, the downloaded file was conveniently located in the Downloads folder and as this should also be the case for you the required commands should be the same. Type cd Downloads followed by shasum -a 256 <filename> where you replace <filename> with the actual file name of your download. Shown below, the file name was ElectrumSV-1.3.12.dmg and if you downloaded this file you also would use shasum -a 256 ElectrumSV-1.3.12.dmg as shown.

Run the 'shasum' application on your downloaded file.

Run the ‘shasum’ application on your downloaded file.

If you find the ElectrumSV-1.3.12.dmg entry in the linked Github list, you can see it matches the shasum checksum result. The case of the letters does not matter, both lower case and upper case are equivalent. If you get a different result, and the command complains that it cannot find the file, then the file is not in the current directory. You need to use the cd command to change the current directory as mentioned above.

GNU Privacy Guard

By installing GNU Privacy Guard (GPG) you have a way to verify that the signatures provided by the developers for the files you download, prove those files came from those developers. This is quite involved to do, but it might be that you are more comfortable with this approach.

Start by downloading and installing GPG from the GPGTools web site. This gives you a way to check signatures for files. The next step is to obtain the keys for the ElectrumSV developers, and to register them with GPG. This is a little complicated so you need to follow these steps.

Open the pubkeys folder from the official ElectrumSV Github repository in Safari. You should see two files listed, rt121212121.asc and kyuupichain.asc. For each file perform the following key import actions.

Key import

Remember that this has to be done for all of the listed public keys in the ElectrumSV Github folder. Once you are viewing the raw page for a key, select (press Command with a) and copy (press Command and c) the key text.

Select and copy the public key text.

Select and copy the public key text.

As soon as you have copied the key text, the GPG application you installed will signal that it has detected a public key was copied. You will see it’s icon in your dock jumping up and down. Click on it to import the key.

Observe the GPG icon in the dock indicating that it can act on the copied key.

Observe the GPG icon in the dock indicating that it can act on the copied key.

The GPG application will require you to approve the import, so go ahead and do that.

Approve the public key import.

Approve the public key import.

Once the public key is imported, you will see another sheet drop down to tell you if it was imported successfully or not. It will of course be successful.

Observe the successful public key import.

Observe the successful public key import.

You can confirm the key was imported successfully, by observing that it is now present in the list in the GPG application.

Observe the imported public key is present in your GPG application.

Observe the imported public key is present in your GPG application.

Go ahead and import any keys you haven’t imported already, then you are all set to verify the signature of an ElectrumSV download when you need to.

Verify a download

Let’s say you have downloaded ElectrumSV-1.3.12.dmg from the official ElectrumSV downloads page. You now need to find and download the signature for that file, so that you can verify it was created by the ElectrumSV developers. The signatures are located on the official ElectrumSV web site, under it’s download folder. The .dmg you downloaded was for version 1.3.12 so locate the folder by that name, and look inside it. You should see the signature file ElectrumSV-1.3.12.dmg.sig, which is what you need to download ElectrumSV-1.3.12.dmg.

Confirm you have downloaded both the .dmg and the matching .dmg.sig files.

Confirm you have downloaded both the .dmg and the matching .dmg.sig files.

Open the context menu for the ElectrumSV-1.3.12.dmg file (press Control when you click on the file). You will see a Services sub-menu, with an additional OpenPGP: Verify Signature of File beneath it. Click on this verify sub-menu.

Open the context menu and select the OpenPGP verify entry.

Open the context menu and select the OpenPGP verify entry.

The GPG application will verify the .dmg using the detected matching .dmg.sig file and let you know the result.

Observe the verification result.

Observe the verification result.

As you can see the signature was verified. If you want to go through the process of trusting the ElectrumSV keys, there is a link there you can use for next time.

Creating a wallet

From ElectrumSV 1.3 and beyond, a wallet is now a container for your accounts. This guide shows you how to create an empty wallet with no accounts. After creating the wallet, you will of course want to add an account to it, in order to be able to start using it.

Choosing the location and file name

The first step is to choose where to store your wallet, and what it’s file name should be. If you choose not to store your wallet in the default location that ElectrumSV uses, it is likely that you will quickly be able to find it again in the “Recently Opened Wallets” list when you open it again in the future.

Start off at the wallet selection page.

blah

The wallet selection page.

You will be presented with a file dialog that lets you choose where your wallet will be stored, and what it will be named. It defaults to the standard ElectrumSV wallet location on your operating system. Enter a file name, and click “Save” (or press the enter key).

blah

The wallet file name dialog.

Add a mandatory password

The next step is setting a password for your new wallet. We require a password and there is no way to opt out, but you can always enter something like “password” or “123456” if you wish. For now this is also required for hardware and watch-only wallets, where there is no key or seed word data to encrypt.

blah

The wallet file name dialog.

Once you have entered a password, and confirmed it, the “OK” button will become enabled and you can click it (or just press the enter key) to open the new wallet. On doing so, the wallet window will open and you will be presented with the account creation dialog.

blah

The new wallet’s wallet window with account creation dialog.

If you dismiss the dialog either intentionally, or accidentally, before creating an account you can bring it back up by clicking the “Add Account” button.

blah

The receiving tab is disabled.

Congratulations, you have created a new empty wallet. It will not be usable until you have created an account, and various parts of the user interface will indicate this.

Creating an account

If you are reading this, you likely have a new wallet that has no accounts, and you want to add one to it. We support addition of a wide variety of account types:

  • A new “Standard” account. This is the equivalent of creating a new ElectrumSV seed-word based wallet in 1.2.5 and earlier.

  • A multi-signature account. Use this if you are creating a new multi-signature account, or restoring an existing one from master public keys, seed words and so on.

  • Importing from text. Use this to import your seed words, whether Electrum seed words, BIP39 seed words from another wallet, private keys, public keys, master public keys, master private keys, and so on.

  • Importing a hardware wallet. If you have an existing hardware wallet that has a seed set up on it, then you can use this to add an account that links to it and uses it to sign. If you have a hardware wallet that does not have a seed set up on it, you should also be able to use this to set it up unless the device is a Ledger. Do not buy a Ledger.

This guide solely covers creating a “Standard” account.

Adding a new account

On creating a new wallet, the first thing you will be presented with is the window for adding a new account.

The account creation window.

The account creation window.

If you dismiss this window, accidentally or otherwise, you can re-open it by clicking on the “Add Account” button on the left hand side of the wallet window toolbar. Click it and it will open the account wizard which allows all supported types of accounts to be created.

The "Add Account" button highlighted.

The “Add Account” button highlighted.

Creating a new “Standard” Account

Double-click on the “Standard” entry to proceed. Or if you prefer to work for it, click the “Next” button or press the enter key. You will be asked for your password so that the generated seed words and private key data can be encrypted into your wallet. This also verifies you have the ability to really use this wallet, and should able to add an account.

The password dialog.

The password dialog.

You will immediately see that the account has been added to your wallet. You will note that at no point did you have to copy down your new seed words, or confirm them. You will be reminded to back them up by the wallet, and can do so at your leisure and own risk.

The first thing you see on creating your new account.

The first thing you see on creating your new account.

The “Notifications” tab will be shown every time you own your wallet as long as you have not dismissed the “Backup your wallet” notification. It is advised you go and back up your secured data immediately, as it instructs you to.

Receiving a payment

An incoming payment is where you declare that you expect an incoming payment, and an address or payment destination is allocated for you to give out. The wallet then monitors the blockchain for usage of this payment destination for a payment, and closes out the incoming payment when either an expiry time has passed or payment is detected, retrieved and processed.

When you want to create an incoming payment, the first thing you do is go to the “Receive” tab. Here you can see a simple form you fill out to create a new incoming payment, and a list showing existing incoming payments.

The "Receive" tab where incoming payments are created and viewed.

The “Receive” tab where incoming payments are created and viewed.

The minimum information you need to provide when creating an incoming payment is the description. If you provide no amount, it will be closed and considered paid if it receives any payment before the expiration period ends. You can also opt not to provide an expiration period, and have it sit there indefinitely. If it expires before the payer pays, then you can of course scan the blockchain to detect it later.

The "Expected payment" dialog shown when you create an incoming payment.

The “Expected payment” dialog shown when you create an incoming payment.

This list is updated in real time. As the expiration period for an incoming payment ends, an expected payment is marked as expired and we stop watching the blockchain for activity related to it. As we detect activity related to an expected payment, we process those transactions and if there is no requested amount or the incoming value in those transactions is greater than or equal to the requested amount we mark the expected payment as paid and stop watching the blockchain for activity related to it.

The incoming payment list at the bottom of the "Receive" tab.

The incoming payment list at the bottom of the “Receive” tab.

Giving out the payment destination

There are several ways you can give the payment destination for your newly created expected payment, to whomever you expect to pay it.

Copying the raw payment destination

In some cases, you might just want to give the payer the raw payment destination which will either be an address or a BIP276 script.

Copying the raw payment destination.

Copying the raw payment destination.

Using a QR code

If the other party is standing there with you, you can show them the expected payment dialog and they can take a photo of the QR code with their wallet. Their wallet will extract the address and streamline the payment process.

The QR code provided in the expected payment dialog.

The QR code provided in the expected payment dialog.

Identifying incoming payments

In the legacy model, which is still the most common one, payments are fire and forget. The payer constructs a transaction and broadcasts it to the blockchain. Then when your wallet gets a notification a payment of interest has appeared in the blockchain, it retrieves that transaction and factors it into the related account.

The history tab when awaiting an incoming payment.

The history tab when awaiting an incoming payment.

With this model, the wallet has no idea a payment is incoming until it arrives out of the blue. A new and better model is available in the form of Paymail, but ElectrumSV does not have the service infrastructure to support it at this time. We are however working towards it.

Making a payment

If you are reading this, you probably want to know how to make a payment. We currently only support making payments in the following ways:

  • Payment to a Bitcoin address.

  • Payment to a BIP276 address.

  • Payment to a Bitcoin script.

This guide solely covers payment to an address. It is not recommended you pay to a Bitcoin script unless you are an expert.

Paying to yourself

At this point you should have a wallet with a standard account. You should also have an address from another party, that you can make a payment to. However for the purpose of this guide, you can make a payment to yourself, if you have no-one else to currently pay.

Start off on the receiving tab.

Highlighted areas on the receiving tab.

Highlighted areas on the receiving tab.

As you will be paying to yourself, copy the shown address. The best way to do this is to click on the copy button, which will copy it to the clipboard. You will use this address as you would the address for any other party.

Paying to an address

Ensure your wallet window is now showing the send tab. Select the “Pay to” field and paste in the address you wish to make a payment to.

Highlighted areas on the send tab.

Highlighted areas on the send tab.

After pasting in the address, enter a nominal amount of Bitcoin SV to send, where your wallet has sufficient funds to do so.

The filled out send tab.

The filled out send tab.

Important

If you are paying to addresses a good practice is to make what is called a pilot payment first, where you pay a small amount you can afford to lose, before paying the larger full amount.

Click the “Send” button to start the payment process.

The password confirmation dialog.

The password confirmation dialog.

Ensure that both the amount you are sending and the mining fee are the appropriate amounts, then enter your password and click “OK”. The “OK” button only becomes enabled when you have entered your password correctly. The transaction will broadcast, and you should receive a confirmation that the payment was made.

The payment sent dialog.

The payment sent dialog.

The confusing sequence of letters and numbers is actually the ID of the transaction that contained your payment. This can be used to look up your payment, if you were to take it and paste it into a web site that indexes the Bitcoin SV blockchain.

The record of payment

At it’s current state of development, the wallet does not have much context about payments made. But you can see the transactions this account is involved in, in the history tab.

The highlighted payment transaction in the history tab.

The highlighted payment transaction in the history tab.

If you had provided a description when making the payment, it would appear here in much the same way as the existing transactions with their “ElectrumSV coin splitting: Your split coins” descriptions.

Scanning the blockchain

As long as there are servers that offer the ability to locate unknown transactions, ElectrumSV will continue to support it. The main use of blockchain scanning, is locating the transactions associated with the seed words or keys that a user imports. Additionally, in the short term before the SPV model is formalised, it can also be used to find unexpected transactions the wallet does not know to look for.

When you import existing seed words or keys

When you create an account by importing existing keys, ElectrumSV should automatically show the blockchain scanning user interface when the wallet window displays that account.

The blockchain scanning window.

The blockchain scanning window.

When you want to run the scanner manually

The button to open the blockchain scanner is featured prominently in the wallet toolbar. It only operates on the currently selected account, but should find any transaction relating to the account that ElectrumSV itself is capable of creating or processing.

The "Scan blockchain" button highlighted in the wallet window.

The “Scan blockchain” button highlighted in the wallet window.

Operating the scanner

The first step is to ensure you can see the blockchain scanning window. This will either be brought up automatically when you create an account from existing keys, or when you click the button in the toolbar.

The blockchain scanning window.

The blockchain scanning window.

Clicking on the “Scan” button will locate any key usage on the blockchain.

The located payments after a scan.

The located payments after a scan.

By expanding the details section, users can see what transactions were located and decide if they want to import them. At this time it is not possible for users to import some but not all of the transactions, but that would be a good idea for improvement.

The optionally viewable details of the located payments.

The optionally viewable details of the located payments.

Once the import process is complete, the user will see the results. It is not guaranteed that all the transactions will be imported. The most likely reason that a transaction won’t be imported is the presence of a conflicting transaction in the account. Another potential reason would be bugs in ElectrumSV.

The results of the payment import process.

The results of the payment import process.

Advanced: Extending the “gap limits”

The BIP32 derivation paths that wallets have standardised on provide consecutive sequences of key usage. An account looks on the blockchain to find transactions related to itself, to work out it’s current balance, available coins to spend and locate historical spends and receipts. This is easily done by starting at the beginning of a derivation path and moving along it until no more transactions are found. When there is a consecutive range at the end of the derivation path of a given length (known as the gap limit) that is known to be unused, it is considered that there are no more transactions.

Standards define both seed words 1, derivation paths 2 and types of payment. One of the benefits of these standards is that with just the seed words a user can change wallets whenever they want. In the short term, while wallets do not do very much besides send and receive coins this works. In the longer term, wallets will do a lot more and it becomes impractical and unsuited. However, there have been bugs in implementation where wallets have gone far beyond the gap limit accidentally. For reasons like this in addition to the simple standardised wallet recovery it is important that ElectrumSV enable users to find transactions beyond the gap limit.

The blockchain scanning advanced options.

The blockchain scanning advanced options.

1

BIP39 seed words standard.

2

BIP32 derivation paths standard.

Problem solving

Why doesn’t my hardware wallet work?

Hardware wallet makers do not provide anywhere near enough support for their devices, and some have a history of making breaking changes that stop them working in ElectrumSV. If your hardware wallet does not work then this is where you should look for some pointers, whether the device is a Trezor, a Ledger, a Keepkey or a Bitbox. Read more about hardware wallet issues.

How do I split my coins?

If you have coins you have not touched since before Bitcoin SV and Bitcoin Cash split from each other, you might want to make sure that you can send one of these without accidentally sending the other. Read more about coin splitting.

How do I deal with problems on MacOS?

Apple have a special operating system which many love. But it comes with some problems. If you use MacOS and something isn’t working right, maybe we have documented it here. Read more about solutions to MacOS problems.

Hardware wallet issues

Ledger

While Ledger as a company do not support Bitcoin SV as a coin on their device, users have been able to use their Ledger devices with ElectrumSV through compatibility with the Bitcoin Cash support.

The Ledger device reports “unverified inputs”

You go to sign your transaction and your Ledger device has a confusing series of screens talking about “unverified inputs” and updating your device and/or software. You can simply step through these screens and select continue. These screens will be shown below, and then a detailed explanation of why you are seeing them will be provided.

The short version is that you can continue past these screens to signing your transaction as you signed it before you started seeing these messages, and it will be as secure as it was then. Just make sure you only sign it once, and if ElectrumSV asks you to resign it over and over not recognising that you did it once, you are probably using malware. Again, see below the screens for an explanation of this in more detail.

Unverified inputs

It should not be necessary to update your Ledger firmware and applications to deal with this.

Update Ledger Live

It should not be necessary to update ElectrumSV, although you should always be using the latest version.

Or third party software

You can cancel the signing of the transaction if you want.

The cancel option

But if you select the “continue” option, the Ledger device will go through the normal transaction signing process.

The continue option

As you might recall, the first step of the correct signing process is to confirm where you are sending funds. And this is where the process is now at. You can go ahead and sign the transaction as you would have in the past before this confusing message.

Now you are past that, the real signing process begins with address confirmation.
Why do I see this “unverified inputs” message?

A theoretical but unlikely exploit was discovered where wallet malware could direct a user to sign a transaction several times, and extract the signed spends from each and combine them into a new transaction which gave a large fee to miners. Trezor wrote an article about it which you can read if you wish. You see this warning because ElectrumSV is not providing the previous transactions in which the spent coins were originally received to the Ledger device.

The simple reason we do not provide the previous transaction data is because Ledger cannot handle it and will break. You can see in the Trezor hardware issues a “DataError: bytes overflow” error, which their users may encounter. We have to provide these transactions to the Trezor devices but they cannot handle them and they break, this means that Trezor users have to be careful not to spend anything other than the simplest of received payments in their transactions themselves and work out what they can and can’t spend themseves. If any of their coins is not simple and cannot be handled by Trezor, they need to bypass their hardware wallet and spend them in an unsafe way by entering their seed words.

Back to Ledger devices. Ledger allow the transaction to be signed without the spent transaction data, and on detecting they do not have it, they show an “unverified inputs” message. This makes it a little lot for Ledger users. They can still sign a spend they are confident is going to the correct places, and not bypass their hardware wallet to do so. Let’s be honest, if someone is going to all the effort of writing malware it has never in the history of malware been to give the stolen coins to miners. The chances of downloading malware are slight, and the chances of downloading malware that gives coins to anyone other than the thief are even slighter.

Trezor

While Trezor as a company do not support Bitcoin SV as a coin on their device, generally Bitcoin SV users have been able to use their Trezor devices with ElectrumSV by having it in the Bitcoin Cash coin mode. However, users are encountering situations where the limitations of the Trezor device result in it no longer being sufficient to work with Bitcoin SV transactions. This likely means that if a user is planning to continue to use a Trezor device, it may require them to jump through hoops to do so.

There are two complications:

  • Later versions of firmware (starting with 1.9.1 for One and 2.3.1 for Model T) require ElectrumSV to pass in parent transactions with the transaction you are signing. ElectrumSV only started supporting this in ElectrumSV 1.3.8 or newer. What this means is that if you are using these later versions of firmware, you must be using ElectrumSV 1.3.8 or newer - or it will error.

  • Bitcoin SV transactions can have large output scripts, larger than what Trezor can handle. Trezor can only sign simple payments and nothing else, but this does not prevent payments from being made into the wallet with additional output scripts added for other reasons that exceed Trezor’s size limit of 15 kilobytes. The parent transaction processing in the Trezor device will error when it encounters these.

Trezor devices are becoming problematic for Bitcoin SV users to use. While they are polished and enjoyable devices to use, unless the large output problem is solved by Trezor, we cannot recommend users buy these devices unless they accept they have to own and deal with these problems. For this reason it is recommended that Trezor users downgrade their devices.

Downgrading your Trezor device

These are Trezor’s firmware version pages, for users who plan to downgrade:

You will need to visit those pages and download the firmware file. Trezor provide instructions on how to downgrade, and let you know how and where to use the file.

Problem: You see a random looking series of numbers and letters
What this problem looks like..

What this problem looks like..

You are using ElectrumSV 1.3.7 or earlier, and your Trezor device has a later version of the firmware. It expects ElectrumSV to have provided the transaction associated with those numbers and letters, but the ElectrumSV version you are using does not know how to or even that it should. You can take the risk of updating to a more recent version of ElectrumSV that supports these parent transactions, and possibly encounter the “DataError: bytes overflow” problem. Or you can downgrade your Trezor firmware to the version listed above.

Problem: You see the message “DataError: bytes overflow”
What this problem looks like..

What this problem looks like..

One of your parent transactions contains not only the coin you are trying to spend, but a large output script. Your Trezor device has a later version of firmware where parent transactions are required to be provided, and the device is choking on the large output. This is a limit in the device itself, and ElectrumSV can do nothing about this. To spend the coin associated with the problem parent transaction, you need to downgrade your firmware to the versions listed above.

Coin splitting

Important

ElectrumSV can only be downloaded from electrumsv.io.

When users have coins that existed before Bitcoin Cash became a separate blockchain from Bitcoin SV, those coins are linked on both blockchains. When they are sent in a wallet on one blockchain, that action can also send them on the other blockchain. Users have had this accidentally happen to them, and the recipient has refused to refund the coins from the blockchain the user did not intend to send on.

If you think you have unsplit coins in your wallet, you can use ElectrumSV’s coin-splitting feature to split them. But keep in mind that you are responsible for your own coins, you should verify for yourself that the splitting worked. And if you are unsure whether your coins need to be split, you can always split them anyway.

How does splitting work?

The process is simple, if the coins are sent on Bitcoin SV in a way that is incompatible with Bitcoin Cash, then the coins are split. Any usage of those specific coins that have been split will from then on be independent on either blockchain.

In order to keep it simple, we only do the simplest case. We make your wallet do a payment to itself that combines all the available coins within it in a way that should be valid on Bitcoin SV and not Bitcoin Cash. This results in one single split coin combining all the individual coins that you had in your wallet before the split.

How you split your coins

Unfortunately, all the coins in the wallet used here are already split. So the following is just going through the process to show you how it works. You can see that this wallet contains a small amount of Bitcoin SV.

Let’s start by changing to the coin-splitting tab:

Selecting the coin-splitting tab.

Selecting the coin-splitting tab.

Once you are looking at the coin-splitting tab, you have two options. Either direct splitting or faucet splitting. We recommend the direct splitting, and do not really support the faucet splitting any more. Direct splitting does not work for hardware wallets, which due to inherent limitations can only work in simple ways.

The coin-splitting tab.

The coin-splitting tab.

Clicking on the direct splitting button will ask you for your password. You will see that the balance of the splitting transaction is the balance of the available coins in the wallet.

Approve the splitting payment.

Approve the splitting payment.

After you enter your password, it will sign and broadcast your transaction. This will happen pretty quickly, and once it is done you will see a dialog letting you know the splitting transaction was broadcast.

The split action completion message.

The split action completion message.

You can now go back to the history tab and see the splitting transaction there, which has an automatic description noting what it was created for.

The history tab with the splitting transaction.

The history tab with the splitting transaction.

In theory, your coins should be split. But again, you are responsible for using them safely and you should ensure that they are really split.

Ensuring your coins are split

Bitcoin is complicated, and in order to really know for yourself that your coins are split, you need to have some level of technical understanding. It’s a lot simpler to just send them to different places on both blockchains, especially safe places like your own wallet’s receiving addresses and check that they get there - so just do that!

Here is one way to do it:

  1. Do a direct split in ElectrumSV.

  2. Open your Bitcoin Cash wallet with the coins that were linked to Bitcoin SV, that you just split in ElectrumSV.

  3. Create a new empty Bitcoin Cash wallet.

  4. Send the coins in your existing Bitcoin Cash wallet to the new Bitcoin Cash wallet.

You can then observe that your Bitcoin Cash is in a new fresh wallet, and your Bitcoin SV is in the old wallet. Neither moved because the other moved, but rather both were moved by you. You might wonder why you need to create a second Bitcoin Cash wallet, and the reason is that this ensures that your Bitcoin SV and Bitcoin Cash are using different keys and it both helps verify they are unlinked and gives you better security going forward.

Hardware wallets

Hardware wallets are extremely limited devices with not much flexibility. They only allow certain types of transactions to be signed, and this does not include the type that the direct splitting method uses.

If you have a hardware wallet, you can try and use faucet splitting. Faucet splitting works by adding a very small Bitcoin SV coin to your wallet, then combining all the available coins in your wallet with that Bitcoin SV coin. This creates a new Bitcoin SV coin which is of course incompatible with the Bitcoin Cash blockchain, and so the coins in the wallet have been split.

Alternatively, if the faucet is not working you can get someone to send you a very small amount of Bitcoin SV and you can accomplish the same thing yourself by sending all the coins in your wallet to one of your own addresses (including that very small amount of Bitcoin SV).

Increasing differences between blockchains

There are an increasing number of changes between Bitcoin Cash and Bitcoin SV. While it is good practice to split your coins just in case you lose your Bitcoin SV when sending your Bitcoin Cash, or lose your Bitcoin Cash when sending your Bitcoin SV, it is possibly becoming easier to avoid it.

High minimum fee on Bitcoin Cash

The Bitcoin Cash servers for the Electron Cash wallet rejected any attempt to broadcast a transaction containing unsplit coins that had 0.5 satoshis per byte fee as too low. Experiments suggest that it is very difficult to get a transaction at this fee level to propagate, maybe nearing impossible.

As the default fee in ElectrumSV is 0.5 satoshis per byte, this could mean that if you send unsplit coins in ElectrumSV the Bitcoin Cash network will completely ignore them. Should you rely on this? No, but it might provide a coincidental safety net for people who do not know they should split their coins.

Schnorr signatures

By default Electron Cash and likely all Bitcoin Cash wallets now use Schnorr signatures. What this means is that the transactions they make should be incompatible with Bitcoin SV as long as the user has not opted out of using Schnorr. So in theory you can just send your coins on Bitcoin Cash and because those Schnorr signatures are used, the coins on Bitcoin Cash have been sent in a way that is incompatible with Bitcoin SV.

The default Electron Cash Schnorr setting.

The default Electron Cash Schnorr setting.

Should you rely on this? Not unless you know for sure that you are using Schnorr signatures in your Bitcoin Cash wallet, and that you have used the correctly.

Thanks

Many thanks to satoshi.io who provided unsplit coins used for testing related to this article.

MacOS issues

Problems launching ElectrumSV

There are various different obstacles users may encounter when they try to run ElectrumSV depending on which version of the operating system they are using. We’ll illustrate each below and explain what it means, and what you can do about it.

“damaged and can’t be opened”

This is a bug in the operating system. What it means is that the file you downloaded is unsigned and they won’t run it or give you the standard ways to work around it involving the Security Center. There is a workaround which you can do, but it involves you using the terminal.

The message shown because of Apple's bug
Workaround

The solution to this is the following steps:

  1. Open the terminal. If you do not know how, you can go to Launchpad enter “terminal” as you would any other application name in the search area, and click on it. Note that you do not enter the ” characters around the word when you search for it.

  2. It is expected that you have the ElectrumSV dmg file you get this error with in your Downloads directory. You can use the “cd” command to change your directory to get there, using cd Downloads.

  3. You need to type something close to xattr -rd com.apple.quarantine <filename>. However, you need to replace “<filename>” with the filename of the ElectrumSV dmg file you are getting this error with. If for instance you downloaded “ElectrumSV-1.4.0b1.dmg”, then you would need to execute the command xattr -rd com.apple.quarantine ElectrumSV-1.4.0b1.dmg.

What this does is it removes the flag Apple put on the file when you downloaded it, to indicate it was not safe. You should be now be able to run it, having applied the workaround.

Startup takes a long time

When you run the dmg and then click on the ElectrumSV logo to start it, does it take a long long time to start? This was never that fast, but it has become slower as we started including the blockchain headers in our application in order to provide a higher quality experience and to prepare for the coming of a new technology called SPV.

Workaround

Install the application and run it as an installed application, rather than launching it from the dmg. This should reduce the time considerably that it takes from when you start the installed application to when you see the first window it opens.

  1. Open the dmg file.

  2. Observe there is an ElectrumSV icon on the left hand side, and a folder on the right hand side with an arrow pointing from the icon to the folder.

  3. Drag the icon into the folder.

ElectrumSV should now be installed and you should be able to use Launchpad to start it or whatever you prefer to do to get applications you have installed to run.

Building on ElectrumSV

How can I access my wallet using the REST API?

For most users, accessing their wallet with the user interface will be fine. But if you have a minimal amount of development skill the availability of the REST API gives you a lot more flexibility. The REST API allows a variety of actions among them loading multiple wallets, accessing different accounts, obtaining payment destinations or scripts from any of the accounts. Perhaps you want to add your own interface for your wallet or maybe automate how you use it. Read more about the REST API.

How would I extend ElectrumSV as a customised wallet server?

The REST API is limited in what it can do by nature. Getting the ElectrumSV development team to add what you want to it, is not guaranteed to happen, may not even be possible and if it was who knows how long it would take. An alternative is to build your own “daemon application” which is a way of extending ElectrumSV from the inside. Read more about customised wallet servers.

Do I have to develop against the existing public blockchains?

ElectrumSV provides a way for developers to do offline or local development. customised wallet servers.

The REST API

Technically, the restapi is an example ‘dapp’ (daemon application). But is nevertheless provided in a format that aims to eventually cover the majority of basic use cases.

This RESTAPI may be subject to slight changes but the example dapp source code is there for users to modify to suit your own specific needs.

Endpoints

get_all_wallets

Get a list of all available wallets

Method

GET

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets

Sample Response

{
    "wallets": [
        "worker1.sqlite"
    ]
}
get_parent_wallet

Get a high-level information about the parent wallet and accounts (within the parent wallet).

Method

GET

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite

Sample Response

{
    "parent_wallet": "worker1.sqlite",
    "accounts": {
        "1": {
            "wallet_type": "Standard account",
            "default_script_type": "P2PKH",
            "is_wallet_ready": true
        }
    }
}
load_wallet

Load the wallet on the daemon (i.e. subscribe to ElectrumX for active keys) and initiate synchronization. Returns a high-level information about the parent wallet and accounts.

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite

Sample Response

{
    "parent_wallet": "worker1.sqlite",
    "accounts": {
        "1": {
            "wallet_type": "Standard account",
            "default_script_type": "P2PKH",
            "is_wallet_ready": true
        }
    }
}
get_account

Get high-level information about a given account

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1

Sample Response

{
    "1": {
        "wallet_type": "Standard account",
        "default_script_type": "P2PKH",
        "is_wallet_ready": true
    }
}
get_coin_state

Get the count of cleared, settled and matured coins.

Method

GET

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/utxos/coin_state

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/utxos/coin_state

Sample Response

{
    "cleared_coins": 11,
    "settled_coins": 700,
    "unmatured_coins": 0
}
get_utxos

Get a list of all utxos.

Method

GET

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/utxos

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/utxos

Sample Response

{
    "utxos": [
        {
            "value": 20000,
            "script_pubkey": "76a91485324d225c81d414fe8a92bf101dba1a59211e8488ac",
            "script_type": 2,
            "tx_hash": "ce7c2fbc25d25d945b4ad539d2b41ead29e1b786a8aa42b2677af28da3f231a0",
            "out_index": 49,
            "keyinstance_id": 13,
            "address": "msfERZdhGaabQmeQ1ks8sHYdCDtxnTfL2z",
            "is_coinbase": false,
            "flags": 0
        },
        {
            "value": 20000,
            "script_pubkey": "76a91488471d45666dadece7f06aca22f1a1cf9a3a534988ac",
            "script_type": 2,
            "tx_hash": "ce7c2fbc25d25d945b4ad539d2b41ead29e1b786a8aa42b2677af28da3f231a0",
            "out_index": 50,
            "keyinstance_id": 12,
            "address": "mswXPFgWJbgvyxkWBFfYjbbaD1DZmFS3ig",
            "is_coinbase": false,
            "flags": 0
        },
    ]
}
get_balance

Get account balance (confirmed, unconfirmed, unmatured) in satoshis.

Method

GET

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/balance

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/utxos/balance

Sample Response

{
    "confirmed_balance": 14999694400,
    "unconfirmed_balance": 98000,
    "unmatured_balance": 0
}
remove

Removes transactions (currently restricted to ‘STATE_SIGNED’ transactions.)

Deleting transactions in the ‘Dispatched’, ‘Cleared’, ‘Settled’ states could cause issues with the utxo set and so is not supported at this time (a DisabledFeatureError will be returned). If you require this feature, please make contact via the Atlantis Slack or the MetanetICU slack.

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/txs

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/txs

Sample Body Payload

{
    "txids": [
        "96eee07f8e2c96e33d457138496958d912042ff4ed7b3b9c74a2b810fa5c3750",
        "469ddc27b8ef3b386bf7451aebce64edfe22d836ad51076c7a82d78f8b4f4cf9",
        "e81472f9bbf2dc2c7dcc64c1f84b91b6214599d9c79e63be96dcda74dcb8103d"
    ]
}

Sample Response

{
    "items": [
        {
            "id": "96eee07f8e2c96e33d457138496958d912042ff4ed7b3b9c74a2b810fa5c3750",
            "result": 200
        },
        {
            "id": "469ddc27b8ef3b386bf7451aebce64edfe22d836ad51076c7a82d78f8b4f4cf9",
            "result": 400,
            "description": "DisabledFeatureError: You used this endpoint in a way that is not supported for safety reasons. See documentation for details (https://electrumsv.readthedocs.io/ )"
        },
        {
            "id": "e81472f9bbf2dc2c7dcc64c1f84b91b6214599d9c79e63be96dcda74dcb8103d",
            "result": 400,
            "description": "Transaction not found"
        }
    ]
}
get_transaction_history

Get transaction history. tx_flags can be specified in the request body. This is an enum representing a bitmask for filtering transactions.

The main `TxFlags` are:

STATE_CLEARED

1 << 20 (received over p2p network and is unconfirmed and in the mempool)

STATE_SETTLED

1 << 21 (received over the p2p network and is confirmed in a block)

STATE_RECEIVED

1 << 22 (received from another party and is unknown to the p2p network)

STATE_SIGNED

1 << 23 (not sent or given to anyone else, but are with-holding and consider the inputs it uses allocated)

STATE_DISPATCHED

1 << 24 (a transaction you have given to someone else, and are considering the inputs it uses allocated)

However, there are other flags that can be set. See electrumsv/constants.py:TxFlags for details.

In the example below, (1 << 23 | 1 << 21) yields 9437184 (to filter for only STATE_SIGNED and STATE_CLEARED transactions)

An empty request body will return all transaction history for this account. Pagination is not yet implemented.

Request

Method

GET

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/txs/history

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/txs/history

Sample Body Payload

{
    "tx_flags": 9437184
}

Sample Response

{
    "history": [
        {
            "txid": "64a9564588f9ebcce4ac52f4e0c8fe758b16dfd6fdb5bd8db5920da317aa15c8",
            "height": 0,
            "tx_flags": 1052720,
            "value": -10200
        },
        {
            "txid": "a6ec24243a79de1b51646d1a46ece854a8f682ff23b4d4afabaebc2bc10ef110",
            "height": 0,
            "tx_flags": 1052720,
            "value": -10200
        }
    ]
}
fetch_transaction

Get the raw transaction for a given hex txid (as a hex string) - must be a transaction in the wallet’s history.

Method

GET

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/txs/fetch

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/txs/fetch

Sample Request Payload

{
    "txid": "d45145f0c2ff87f6cfe5524d46d5ba14932363e927bd5a4af899a9b8fc0ab76f"
}

Sample Response

{
    "tx_hex": "0100000001e59dd2992ed46911bea87af1b4f7ab1edce8e038520f142d2aa219492664d993160000006b483045022100ec97e4887b5dd9bb3c1e0ebd0d5b2b3520aeda4d957de4bf0e06a920c7dd3fe802200be4c58192a7c67930518bf29b30ab49883fcc342ca4ee5815288c6f17d7b486412103ab06ed1f70de1524e34a4e36575993a70ff2c8800958045137d0cc2caf67ec91ffffffff0248260000000000001976a9143ef1b7677ea1ed53400da9719380b4d0373a1b5f88ac10270000000000001976a91403d0de941da4f897a7cd3828b4905fa64190a72f88acce000000"
}
create_tx

Create a locally signed transaction ready for broadcast. A side effect of this is that the utxos associated with the transaction are allocated for use and so cannot be used in any other transaction.

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/txs/create

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/txs/create

Sample Request Payload This example is of a single “OP_FALSE OP_RETURN” output with “Hello World” encoded in Hex. The preceeding 0x0b byte represents a pushdata op code to push the next 11 bytes onto the stack (“68656c6c6f20776f726c64”).

Additional outputs for leftover change will be created automatically.

{
    "outputs": [
        {"script_pubkey":"006a0b68656c6c6f20776f726c64", "value": 0}
    ],
    "password": "test"
}

Sample Response

{
    "txid": "96eee07f8e2c96e33d457138496958d912042ff4ed7b3b9c74a2b810fa5c3750",
    "rawtx": "0100000001cfdec4ce0f10c4148b44163bf6205f53e5ab31f04a57fcaaeb33ef6487e08511000000006b483045022100873bb0dabc0b053be5602ebd1bb1ce143999221317eda8835fdf96a3197b168e022037ac7ad4c5f27beee3805e581b483b418a5298a3c467872d548accdc056321cb412103bf03fd106e69b55fc2041cc862a2c1932367899de4a734ef37b8a8f056792869ffffffff0200000000000000000e006a0b68656c6c6f20776f726c64dd250000000000001976a914c6d2e09ff211db5671ea1a9a08df13703b5a06f988acd5000000"
}
broadcast

Broadcast a rawtx (created with the previous endpoint).

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/txs/broadcast

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/txs/broadcast

Sample Request Payload This example is of a single “OP_FALSE OP_RETURN” output with “Hello World” encoded in Hex. The preceeding 0x0b byte represents a pushdata op code to push the next 11 bytes onto the stack (“68656c6c6f20776f726c64”).

Additional outputs for leftover change will be created automatically.

{
    "rawtx": "0100000001ab9aff89a92c011b5436a0c02eb53cf6328286e5cf5767f309cde5414f657661000000006a473044022050750ec47afa183d3c99e22bc4324c3af83115fb409f966e345f72e0bcfa780302201e5d5920e0164c26f2fee2a71b079a4c4918ec9b269df624f3fb2fd483d6dedc4121038cac099086f38c1298d745f3b67e14bc4ab29a21fab5514111c65e196d430b29ffffffff0200000000000000000e006a0b68656c6c6f20776f726c64dd250000000000001976a914ee8f1e9312200924a406e4c39a2d0685df60924988acce000000"
}

Sample Response

{
    "txid": "7ff0fcf6de91ffa71ef145e31d0bffe31467ecaa125a8db307cf9066fea55db5"
}
create_and_broadcast

Atomically creates and broadcasts a transaction. If any errors occur, the intermediate step of creating a signed transaction will be reversed (i.e. the transaction will be deleted and the utxos freed for use).

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/txs/create_and_broadcast

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/txs/create_and_broadcast

Sample Request Payload This example is of a single “OP_FALSE OP_RETURN” output with “Hello World” encoded in Hex. The preceeding 0x0b byte represents a pushdata op code to push the next 11 bytes onto the stack (“68656c6c6f20776f726c64”).

Additional outputs for leftover change will be created automatically.

{
    "outputs": [
        {"script_pubkey":"006a0b68656c6c6f20776f726c64", "value": 0}
    ],
    "password": "test"
}

Sample Response

{
    "txid": "469ddc27b8ef3b386bf7451aebce64edfe22d836ad51076c7a82d78f8b4f4cf9"
}
split_utxos

Creates and broadcasts a coin-splitting transaction i.e. it breaks up existing utxos into a specified number of new utxos with the desired “split_value” (satoshis). “split_count” represents the maximum number of splitting outputs for the transaction. “desired_utxo_count” determines when the desired utxo count has been reached (i.e. if you have 200 utxos but “desired_utxo_count” is 220 then the next coin splitting transaction will create 20 more utxos.

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/txs/split_utxos

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/txs/split_utxos

Sample Request Payload

{
    "split_value": 10000,
    "split_count": 100,
    "password": "test",
    "desired_utxo_count": 1000
}

Sample Response

{
    "txid": "42329848db94cb16379b0c8898eb2b98542fb25d9257a47663c3fac7b0f49938"
}

Regtest only endpoints

If you try to access these endpoints when not in RegTest mode you will get back a 404 error because the endpoint will not be available.

generate_blocks

Tops up the RegTest wallet from the RegTest node wallet (new blocks may be generated to facilitate this process).

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/generate_blocks

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/generate_blocks

Sample Request Payload

{
    "nblocks": 3
}

Sample Response

{
    "txid": [
        "72d1270d0b3ad4c71d8257db8d6f880186108152534658ae6a127b616795530d"
    ]
}
create_new_wallet

This will create a new wallet - in this example “worker1.sqlite”.

Method

POST

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/create_new_wallet

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/create_new_wallet

Sample Request Payload

{
    "password": "test"
}

Sample Response

{
    "new_wallet": "G:\\electrumsv_official\\electrumsv1\\regtest\\wallets\\worker1.sqlite"
}
transaction state websocket

This websocket is for tracking transaction state changes. One main use case might be to wait on the websocket pending transaction confirmation (i.e. ‘StateSettled’). But it is not limited to this transaction state.

Supported States:

StateCleared

1 << 20 (received over p2p network and is unconfirmed and in the mempool)

StateSettled

1 << 21 (received over the p2p network and is confirmed in a block)

May be supported later:

StateReceived

1 << 22 (received from another party and is unknown to the p2p network)

Request

Method

GET

Content-Type

application/json

Endpoint

http://127.0.0.1:9999/v1/{network}/dapp/wallets/{wallet_name}/{account_id}/websocket/text-events

Regtest example

http://127.0.0.1:9999/v1/regtest/dapp/wallets/worker1.sqlite/1/websocket/text-events

Sample Websocket message

{
    "txids": ["3c26c76acebffdd614d6a829bc014114803ba650710652d67837718e467a94ab"]
}

Sample Response

{
    "txid": "3c26c76acebffdd614d6a829bc014114803ba650710652d67837718e467a94ab",
    "tx_flags": 2109552
}

Sample Error Response

{
    'code': 40000,
    'message': "some error message goes here"
}

Wallet as a service

As the Bitcoin SV ecosystem matures services will become available that allow businesses to outsource the wallet management and the services necessary for their products. There is a sizeable advantage to this, as it allows the business to focus on the products and avoid complicated and rather standard work that there is a benefit to outsourcing.

For the businesses that want or even need to be in control of their own wallet and infrastructure, they can treat ElectrumSV as a common open source base, and extend it with their own proprietary functionality. An starting point for this approach can be found in the example application on Github.

This documentation will be fleshed out as time allows.

Local or offline development

A command-line based environment is provided for local Bitcoin SV development. There is no requirement to be online while using it (after the components are installed).

More details about the SDK can be found here: https://electrumsv-sdk.readthedocs.io/

Essentially the SDK allows a developer to run:

  • A RegTest Bitcoin node

  • A RegTest ElectrumX instance (which is the currently used chain indexing service).

  • A RegTest ElectrumSV wallet server with REST API or alternatively in GUI mode.

  • The Merchant API which runs alongside the Bitcoin node and will be used for transaction broadcasting and merkle proofs.

  • A mock service that acts as an intermediate agent for payment requests, invoices and other SPV / p2p functionalities.

With these processes running it allows for a faster development iteration cycle and the ability to test the correctness of any new changes. This is particularly so for things like processing of confirmed transactions and reorgs - which is not feasible on public testnets (e.g. waiting for a new block to be mined or for a reorg to happen).

A useful workflow for debugging can be to set a “pdb” break point and run the functional tests which then enters the debugger interactive terminal.

For details about formal, automated functional testing, please see the sections:

  • functional tests

  • stresstesting

The SDK also makes it trivial to reset all services back to a “clean slate” and to perform deterministic (i.e. repeatable) testing - especially for simulated reorgs.

Functional tests

The functional tests are a set of tests that use the REST API to manipulate the state of a ‘live’ RegTest wallet and check that the state changes are matching what is expected. Eventually, the REST API should mature to cover all functionality available through the GUI, allowing automation of any wallet tasks as well as full end-to-end integration testing coverage.

The functional tests are run as part of the Azure pipeline for any commits to any new feature branch or pull requests but can also be run locally (and offline) provided a few dependencies are installed.

A few examples of functional tests are:

  • A simulated reorg test (via the RegTest SDK) in which wallet transactions are affected and move to a new block height with a new merkle branch. The database and general wallet state is checked for consistency before and after the reorg.

  • Loading the wallet on the daemon.

  • Getting the account details.

  • Getting utxos before and after topping up the wallet with new coins.

  • Getting utxos before and after splitting a coin into smaller outputs.

  • Concurrent transaction broadcasting to check the broadcast pathway and as a basic check for data races.

These tests give a broad-brush coverage of many different code paths and as the REST API grows to cover all GUI interactions will give assurances about:

  • Correctness of wallet state.

  • Regressions at the wallet server level that could in turn affect the user experience.

Installation of dependencies

  1. Install pytest pre-requisites:

    python3 -m pip install pytest pytest-cov pytest-asyncio pytest-timeout electrumsv_node openpyxl
    
  2. Install the ElectrumSV-SDK (follow instructions here: https://electrumsv-sdk.readthedocs.io/ ) and then do:

    electrumsv-sdk install node
    electrumsv-sdk install electrumx
    electrumsv-sdk install --repo=$PWD electrumsv
    

This will install the repositories and dependencies for these components.

Run the functional tests

The SDK components should be stopped before running the tests as the tests automate resetting and starting these services - it will fail if they are already running.

Run the functional tests with pytest like this:

python3 -m pytest -v -v -v contrib/functional_tests/functional

Which should output something like (but with verbose logging output):

contrib\functional_tests\functional\test_reorg.py::TestReorg::test_reorg PASSED
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_get_all_wallets PASSED                                                              [ 25%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_load_wallet PASSED                                                                  [ 33%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_websocket_wait_for_mempool PASSED                                                   [ 41%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_websocket_wait_for_confirmation PASSED                                              [ 50%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_get_parent_wallet PASSED                                                            [ 58%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_get_account PASSED                                                                  [ 66%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_get_utxos_and_top_up PASSED                                                         [ 75%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_get_balance PASSED                                                                  [ 83%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_concurrent_tx_creation_and_broadcast PASSED                                         [ 91%]
contrib\functional_tests\functional\test_restapi.py::TestRestAPI::test_create_and_broadcast_exception_handling PASSED

============================================================= 11 passed, 1 skipped, 0 failed in 49.53s ==========================================================

Logging

There is a pytest.ini file in contrib/functional_tests/pytest.ini with these settings:

[pytest]
log_cli=true
log_level=INFO

If you are finding the logging details distracting or you want more verbose logging you can refer to the pytest documentation and change the pytest.ini settings as needed.

Benchmarks

The benchmarks use the REST API running on a ‘live’ RegTest wallet server to produce global metrics about performance.

Currently this includes the rate of transaction broadcast and processing and its interaction with the size and composition of the utxo set. It is likely that the benchmarks will be added to and changed from what they are today (perhaps with an ergonimic way of gathering profiling data at runtime).

The benchmarks are not run in the Azure pipeline in order to avoid slowing it down. Furthermore, the results would not be consistent across time because the underlying hardware and strain on the Azure agent will vary over time. Therefore, the benchmarks should be run on your local development machine where these factors can be controlled for.

Installation of dependencies

  1. Install pytest pre-requisites:

    python3 -m pip install pytest pytest-cov pytest-asyncio pytest-timeout electrumsv_node openpyxl
    
  2. Install the ElectrumSV-SDK (follow instructions here: https://electrumsv-sdk.readthedocs.io/ ) and then do:

    electrumsv-sdk install node
    electrumsv-sdk install electrumx
    electrumsv-sdk install --repo=$PWD electrumsv
    

This will install the repositories and dependencies for these components.

Settings

The SDK components should be stopped before running the tests as the tests automate resetting and starting these services - it will fail if they are already running.

The current stresstest automates the preparatory measure of splitting utxos up to a predefined count: DESIRED_UTXO_COUNT which defaults to 5000 utxos.

There is also a parameter for how many coin splitting outputs there are per coin splitting transaction: SPLIT_TX_MAX_OUTPUTS which defaults to 2000. This is included because prior experience found that this affected throughput.

The number of worker tasks: N_TX_CREATION_TASKS (which run as coroutines on the asyncio event loop) defaults to 100. I recommend leaving this unchanged.

The total number of transactions that are created and broadcast is defined by the environment variable: STRESSTEST_N_TXS and defaults to 2000. If you want to perform a prolonged stresstest you could raise this significantly.

The timer starts when the initial coin splitting has completed and stops when all transactions have been:

  • Created and signed

  • Broadcast to the network

  • Fully confirmed and processed (there is an automated background task that mines blocks and a websocket for waiting on transaction state changes)

In summary; The default settings (as environment variables) are:

N_TX_CREATION_TASKS = 100
DESIRED_UTXO_COUNT = 5000
SPLIT_TX_MAX_OUTPUTS = 2000
STRESSTEST_N_TXS = 2000

Run with pytest

Run the benchmark:

python3 -m pytest -v contrib/functional_tests/stresstesting

The result is exported to:

contrib/functional_tests/stresstesting/.benchmarks/bench_result.xlsx

With this format:

_images/example_bench_results.png

Run with a matrix of settings

There is also a python script for running the benchmark multiple consecutive times with a matrix of different settings and appending the results to the excel spreadsheet:

python3 contrib/functional_tests/stresstesting/run_stresstest_matrix.py

The initial output will look like this:

============================== Test Params Matrix ==============================
TestParams(number_txs=2000, total_utxo_count=2000, max_split_tx_outputs=500)
TestParams(number_txs=2000, total_utxo_count=2000, max_split_tx_outputs=2000)
TestParams(number_txs=2000, total_utxo_count=5000, max_split_tx_outputs=500)
TestParams(number_txs=2000, total_utxo_count=5000, max_split_tx_outputs=2000)
TestParams(number_txs=2000, total_utxo_count=10000, max_split_tx_outputs=500)
TestParams(number_txs=2000, total_utxo_count=10000, max_split_tx_outputs=2000)
TestParams(number_txs=5000, total_utxo_count=2000, max_split_tx_outputs=500)
TestParams(number_txs=5000, total_utxo_count=2000, max_split_tx_outputs=2000)
TestParams(number_txs=5000, total_utxo_count=5000, max_split_tx_outputs=500)
TestParams(number_txs=5000, total_utxo_count=5000, max_split_tx_outputs=2000)
TestParams(number_txs=5000, total_utxo_count=10000, max_split_tx_outputs=500)
TestParams(number_txs=5000, total_utxo_count=10000, max_split_tx_outputs=2000)
================================================================================

This can be thought of as an example script that can be tweaked to your own needs.

Logging

There is a pytest.ini file in contrib/functional_tests/pytest.ini with these settings:

[pytest]
log_cli=true
log_level=INFO

If you are finding the logging details distracting or you want more verbose logging you can refer to the pytest documentation and change the pytest.ini settings as needed.

The wallet database

Each wallet is stored in it’s own SQLite database. The current version of ElectrumSV at the time of writing, 1.4.0b1, uses the database schema version 28. This schema is include for reference purposes and cannot be used to a working wallet.

Each version of ElectrumSV includes migration code that applies any needed changes to older versions of the wallet. This database format is pretty solid at this point, but it is a work in progress. There are many other things ElectrumSV will need to support in the future.

Database schema

  1-- Schema version 28.
  2-- This schema is provided for reference purposes only.
  3--
  4-- Using it to create an ElectrumSV wallet is not supported, and will not work.
  5
  6BEGIN TRANSACTION;
  7
  8CREATE TABLE "AccountTransactions" (
  9    tx_hash BLOB NOT NULL,
 10    account_id INTEGER NOT NULL,
 11    flags INTEGER NOT NULL DEFAULT 0,
 12    description TEXT DEFAULT NULL,
 13    date_created INTEGER NOT NULL,
 14    date_updated INTEGER NOT NULL,
 15    FOREIGN KEY (account_id) REFERENCES Accounts (account_id),
 16    FOREIGN KEY (tx_hash) REFERENCES Transactions (tx_hash)
 17);
 18
 19CREATE TABLE Accounts (
 20    account_id INTEGER PRIMARY KEY,
 21    default_masterkey_id INTEGER DEFAULT NULL,
 22    default_script_type INTEGER NOT NULL,
 23    account_name TEXT NOT NULL,
 24    date_created INTEGER NOT NULL,
 25    date_updated INTEGER NOT NULL,
 26    FOREIGN KEY(default_masterkey_id) REFERENCES MasterKeys (masterkey_id)
 27);
 28
 29CREATE TABLE Invoices (
 30    invoice_id INTEGER PRIMARY KEY,
 31    account_id INTEGER NOT NULL,
 32    tx_hash BLOB DEFAULT NULL,
 33    payment_uri TEXT NOT NULL,
 34    description TEXT NULL,
 35    invoice_flags INTEGER NOT NULL,
 36    value INTEGER NOT NULL,
 37    invoice_data BLOB NOT NULL,
 38    date_expires INTEGER DEFAULT NULL,
 39    date_created INTEGER NOT NULL,
 40    date_updated INTEGER NOT NULL,
 41    FOREIGN KEY (account_id) REFERENCES Accounts (account_id),
 42    FOREIGN KEY (tx_hash) REFERENCES Transactions (tx_hash)
 43);
 44
 45CREATE TABLE KeyInstanceScripts (
 46    keyinstance_id INTEGER NOT NULL,
 47    script_type INTEGER NOT NULL,
 48    script_hash BLOB NOT NULL,
 49    date_created INTEGER NOT NULL,
 50    date_updated INTEGER NOT NULL,
 51    FOREIGN KEY (keyinstance_id) REFERENCES KeyInstances (keyinstance_id)
 52);
 53
 54CREATE TABLE "KeyInstances" (
 55    keyinstance_id INTEGER PRIMARY KEY,
 56    account_id INTEGER NOT NULL,
 57    masterkey_id INTEGER DEFAULT NULL,
 58    derivation_type INTEGER NOT NULL,
 59    derivation_data BLOB NOT NULL,
 60    derivation_data2 BLOB DEFAULT NULL,
 61    flags INTEGER NOT NULL,
 62    description TEXT DEFAULT NULL,
 63    date_created INTEGER NOT NULL,
 64    date_updated INTEGER NOT NULL,
 65    FOREIGN KEY(account_id) REFERENCES Accounts (account_id) FOREIGN KEY(masterkey_id) REFERENCES MasterKeys (masterkey_id)
 66);
 67
 68CREATE TABLE MasterKeys (
 69    masterkey_id INTEGER PRIMARY KEY,
 70    parent_masterkey_id INTEGER DEFAULT NULL,
 71    derivation_type INTEGER NOT NULL,
 72    derivation_data BLOB NOT NULL,
 73    date_created INTEGER NOT NULL,
 74    date_updated INTEGER NOT NULL,
 75    FOREIGN KEY(parent_masterkey_id) REFERENCES MasterKeys (masterkey_id)
 76);
 77
 78CREATE TABLE PaymentRequests (
 79    paymentrequest_id INTEGER PRIMARY KEY,
 80    keyinstance_id INTEGER NOT NULL,
 81    state INTEGER NOT NULL,
 82    description TEXT DEFAULT NULL,
 83    expiration INTEGER DEFAULT NULL,
 84    value INTEGER DEFAULT NULL,
 85    date_created INTEGER NOT NULL,
 86    date_updated INTEGER NOT NULL,
 87    FOREIGN KEY(keyinstance_id) REFERENCES KeyInstances (keyinstance_id)
 88);
 89
 90CREATE TABLE ServerAccounts (
 91    server_type INTEGER NOT NULL,
 92    url TEXT NOT NULL,
 93    account_id INTEGER NOT NULL,
 94    encrypted_api_key TEXT DEFAULT NULL,
 95    fee_quote_json TEXT DEFAULT NULL,
 96    date_last_connected INTEGER DEFAULT 0,
 97    date_last_tried INTEGER DEFAULT 0,
 98    date_created INTEGER NOT NULL,
 99    date_updated INTEGER NOT NULL,
100    FOREIGN KEY (server_type, url) REFERENCES Servers (server_type, url),
101    FOREIGN KEY (account_id) REFERENCES Accounts (account_id)
102);
103
104CREATE TABLE Servers (
105    server_type INTEGER NOT NULL,
106    url TEXT NOT NULL,
107    encrypted_api_key TEXT DEFAULT NULL,
108    flags INTEGER NOT NULL DEFAULT 0,
109    fee_quote_json TEXT DEFAULT NULL,
110    date_last_connected INTEGER DEFAULT 0,
111    date_last_tried INTEGER DEFAULT 0,
112    date_created INTEGER NOT NULL,
113    date_updated INTEGER NOT NULL
114);
115
116CREATE TABLE TransactionInputs (
117    tx_hash BLOB NOT NULL,
118    txi_index INTEGER NOT NULL,
119    spent_tx_hash BLOB NOT NULL,
120    spent_txo_index INTEGER NOT NULL,
121    sequence INTEGER NOT NULL,
122    flags INTEGER NOT NULL,
123    script_offset INTEGER,
124    script_length INTEGER,
125    date_created INTEGER NOT NULL,
126    date_updated INTEGER NOT NULL,
127    FOREIGN KEY (tx_hash) REFERENCES Transactions (tx_hash)
128);
129
130CREATE TABLE "TransactionOutputs" (
131    tx_hash BLOB NOT NULL,
132    txo_index INTEGER NOT NULL,
133    value INTEGER NOT NULL,
134    keyinstance_id INTEGER DEFAULT NULL,
135    flags INTEGER NOT NULL,
136    script_type INTEGER DEFAULT 0,
137    script_hash BLOB NOT NULL DEFAULT x '',
138    script_offset INTEGER DEFAULT 0,
139    script_length INTEGER DEFAULT 0,
140    spending_tx_hash BLOB NULL,
141    spending_txi_index INTEGER NULL,
142    date_created INTEGER NOT NULL,
143    date_updated INTEGER NOT NULL,
144    FOREIGN KEY (tx_hash) REFERENCES Transactions (tx_hash),
145    FOREIGN KEY (keyinstance_id) REFERENCES KeyInstances (keyinstance_id)
146);
147
148CREATE TABLE Transactions (
149    tx_hash BLOB PRIMARY KEY,
150    tx_data BLOB DEFAULT NULL,
151    proof_data BLOB DEFAULT NULL,
152    block_height INTEGER DEFAULT NULL,
153    block_position INTEGER DEFAULT NULL,
154    fee_value INTEGER DEFAULT NULL,
155    flags INTEGER NOT NULL DEFAULT 0,
156    description TEXT DEFAULT NULL,
157    date_created INTEGER NOT NULL,
158    date_updated INTEGER NOT NULL,
159    locktime INTEGER DEFAULT NULL,
160    version INTEGER DEFAULT NULL,
161    block_hash BLOB DEFAULT NULL
162);
163
164CREATE TABLE WalletData (
165    key TEXT NOT NULL,
166    value TEXT NOT NULL,
167    date_created INTEGER NOT NULL,
168    date_updated INTEGER NOT NULL
169);
170
171CREATE TABLE WalletEvents (
172    event_id INTEGER PRIMARY KEY,
173    event_type INTEGER NOT NULL,
174    event_flags INTEGER NOT NULL,
175    account_id INTEGER,
176    date_created INTEGER NOT NULL,
177    date_updated INTEGER NOT NULL,
178    FOREIGN KEY(account_id) REFERENCES Accounts (account_id)
179);
180
181CREATE UNIQUE INDEX idx_WalletData_unique ON WalletData(key);
182
183CREATE UNIQUE INDEX idx_Invoices_unique ON Invoices(payment_uri);
184
185CREATE UNIQUE INDEX idx_AccountTransactions_unique ON AccountTransactions(tx_hash, account_id);
186
187CREATE UNIQUE INDEX idx_TransactionOutputs_unique ON TransactionOutputs(tx_hash, txo_index);
188
189CREATE UNIQUE INDEX idx_TransactionInputs_unique ON TransactionInputs(tx_hash, txi_index);
190
191CREATE UNIQUE INDEX idx_KeyInstanceScripts_unique ON KeyInstanceScripts(keyinstance_id, script_type);
192
193CREATE VIEW TransactionReceivedValues (account_id, tx_hash, keyinstance_id, value) AS
194SELECT
195    ATX.account_id,
196    ATX.tx_hash,
197    TXO.keyinstance_id,
198    TXO.value
199FROM
200    AccountTransactions ATX
201    INNER JOIN TransactionOutputs TXO ON TXO.tx_hash = ATX.tx_hash
202    INNER JOIN KeyInstances KI ON KI.keyinstance_id = TXO.keyinstance_id
203WHERE
204    TXO.keyinstance_id IS NOT NULL
205    AND KI.account_id = ATX.account_id;
206
207CREATE VIEW TransactionSpentValues (account_id, tx_hash, keyinstance_id, value) AS
208SELECT
209    ATX.account_id,
210    ATX.tx_hash,
211    PTXO.keyinstance_id,
212    PTXO.value
213FROM
214    AccountTransactions ATX
215    INNER JOIN TransactionInputs TXI ON TXI.tx_hash = ATX.tx_hash
216    INNER JOIN TransactionOutputs PTXO ON PTXO.tx_hash = TXI.spent_tx_hash
217    AND PTXO.txo_index = TXI.spent_txo_index
218    INNER JOIN KeyInstances KI ON KI.keyinstance_id = PTXO.keyinstance_id
219WHERE
220    PTXO.keyinstance_id IS NOT NULL
221    AND KI.account_id = ATX.account_id;
222
223CREATE VIEW TransactionValues (account_id, tx_hash, keyinstance_id, value) AS
224SELECT
225    account_id,
226    tx_hash,
227    keyinstance_id,
228    value
229FROM
230    TransactionReceivedValues
231UNION
232ALL
233SELECT
234    account_id,
235    tx_hash,
236    keyinstance_id,
237    - value
238FROM
239    TransactionSpentValues;
240
241CREATE UNIQUE INDEX idx_Servers_unique ON Servers(server_type, url);
242
243CREATE UNIQUE INDEX idx_ServerAccounts_unique ON ServerAccounts(server_type, url, account_id);
244
245COMMIT;

The ElectrumSV project

Perhaps you are a developer who already helps out on the ElectrumSV project, or you who would like to get involved in some way, or you are just curious about the processes and information related to project management and development. If so, this is the information you want.

How can you contribute?

There are many ways that you can help the ElectrumSV project improve. If you want something to work in a different way, you can work on making it different and offer us the changes. If you feel the documentation could be better, you can improve it and offer us the changes. If you want ElectrumSV or anything related to it in your native language, you can offer to do the work to translate it. And that’s just a few of the possibilities. Read more about contributing.

What platforms and platform versions do we make releases for?

Our builds are created using both third-party dependencies and the Azure Devops services. There are certain limitations that each of these two things imposes on the releases we can make. Read more about the relevant choices and limitations involved in our releases.

Where is the continuous integration and how is it used?

We use Microsoft’s Azure DevOps services for continuous integration. Microsoft provide generous levels of free usage to open source projects hosted on Github. This is used to do a range of activities for every change we make to the source code, from running the unit tests against each change on each supported operating system, to creating a packaged release for each system that can be manually tested. Read more about our use of continuous integration.

What is the process of releasing a new version?

Because we generate packaged releases for every change we make, with a bit of extra work we can generate properly prepared public releases. This involves changing the source code so that the release has the content changes required for new version, and also publishing the release and updating the web site to have the content changes required to offer it for download. Read more about the release process.

How you can contribute

What are some of the ways you might contribute to ElectrumSV?

  • Contributing translations.

  • Contributing new features.

  • Contributing bug fixes.

  • Reporting problems.

Translations

Anyone wishing to contribute translations of the text in the ElectrumSV user interface, can do so by the ElectrumSV project on Crowdin. Once you’ve done entering translations let us know, and we’ll do the process of exporting the latest data from Crowdin so that your transaction work gets used.

New features

Be aware that you should check with us before starting work on a feature you are hoping we will accept into ElectrumSV. If we accept a new feature, we then have to maintain it and accept the extra work involved on top of that required for support requests, current features and bug fixes. And it may be that depending on the feature we cannot remove it later, if users become reliant on it or have data that requires it to be present.

Bug fixes

We welcome bug fixes for existing problems, whether they are problems you encounter yourself or ones that you see others have reported that have not already been fixed. You can find our existing bugs in our issue tracker on Github.

Reporting problems

Even if you do not have the experience, skill or inclination to attempt to fix problems you encounter, it would be appreciated if you could report them to us. And if you can take the time to describe what you were doing when you encountered the problem, it helps us fix the problems much more easily. You can report bugs using our template in our issue tracker on Github.

Continuous integration

As Microsoft provide generous levels of free usage to open source projects hosted on Github through their Azure DevOps service, ElectrumSV makes use of it for a range of purposes. Every time changes are pushed to Github, the following tasks are run:

  • Unit tests on Windows, MacOS and Linux.

  • Linting.

  • Type checking.

  • Code coverage analysis.

  • Producing releases.

While Azure DevOps will do these things against each individual commit, we have configured the project to only do it against the latest commit.

Releases

There are two goals in having CI produce build files:

  • We can use it to produce the build files we release publically.

  • Members of the public can access and download build files for any build.

Using CI to produce official release files

By having CI produce the build files, this allows a developer to offload the processing work from their own computer and carry on working on other tasks. In addition there is some security in having the build files made within CI, where the CI obtains the source code directly from the latest commit on Github. And on generating the build files, also produces SHA256 hashes that can be used to validate the content at any later time.

Benefits of public build access

If a user is experiencing a bug, a developer can fix it and push the fix to Github. This will result in an automatic build on Azure DevOps, and if it succeeds will produce build files. The developer can point the user to the build, and although the user may not have an account with Azure DevOps they still have enough access that they can download build artifacts like the build files.

Releases

Currently ElectrumSV only builds releases for Windows and MacOS. It is expected that Windows users are using at least Windows 10, and MacOS users are using 10.15 or later. We intentionally do not provide either Linux builds or support any form of packaging, and Linux users are expected to get it running from source.

Some of the reasons we do this are intentional, and others are technical limitations that are either imposed by our build environment or the dependencies we use. This document is intended to detail those reasons, both for reference by our users and developers.

Platforms

Developer resources are limited, and we need to focus it where it matters. This is the main reason relating to our platform-related release choices. Even if a community member contributes changes to add support for dated platform versions, accepting those changes can impose heavy ongoing costs on developer time and even unacceptable limitations on development for recent platform versions.

Windows

ElectrumSV Windows builds are for Windows 10 or above. It is possible they work on earlier versions of Windows, but we will neither test that it works or make unreasonable changes to keep it working.

MacOS

ElectrumSV MacOS builds are currently limited to 10.15 and above.

Build environment

Our releases are made in our CI environment provided by Microsoft. The release build the CI environment creates currently requires MacOS 10.15.

Dependency: Qt

ElectrumSV uses the Qt user interface package. Each updated version of Qt requires more and more recent versions of MacOS. At the time of writing, we use 5.15 but we plan to update to 6.1 when we get the time.

  • Qt 5.15 needs MacOS 10.13 or later.

  • Qt 6.0 needs MacOS 10.14 or later.

  • Qt 6.1 needs MacOS 10.14 or later.

Linux

ElectrumSV does not provide any builds or packages for Linux.

People have offered to contribute code to support various Linux packaging systems, but we have had to refuse that. It is very little work to take in that code and produce those packages, but it too much work to test them and verify they work on all the different Linux distributions. We will never accept Linux packaging support for this reason.

What we would be willing to accept, is AppImage support, where the AppImage build runs on at least all mainstream Linux distributions without any extra work. Unfortunately, there has been no interest from Linux users on working on this and contributing that code. The ElectrumSV developers will need to produce the builds, test them and polish them - so there are quality requirements.

Important

Do you want ElectrumSV to have AppImage support for Linux? Get in touch with the ElectrumSV developers and work out what we require in any acceptable solution.

Release process

There are a lot of steps to releasing a new version of ElectrumSV. This document is intended to lay out the entire proces and some of the reasoning behind it, so that any developer can jump in and do a release if necessary. In addition, formalising the release process ensures that nothing is accidentally left out due to any informal and casually documented process leading to an oversight of various steps.

Initial preparation

When it is time to release a new version, the first step is to freeze the release branch in Github and prevent introduction of any changes that introduce new functionality or change existing functionality. This is an exercise in self restraint, rather than anything that is done to programmatically disallow these changes to be made.

Writing an article

An initial outline of a release article is written, including the featured changes that will be highlighted. Mostly this involves taking the last article, removing all the changes that were included in the previous version, and putting the new version’s changes in their place using the same format. The key goal of these articles is to illustrate these changes and help users visualise them even if they skim through the article, and it should include screenshots at every possible opportunity.

For each change featured in a release article:

  • A link should be provided to any issue that exists in relation to that change.

  • A link should be provided to every code change made to the source code in the making of the given change.

Updating the version

The version number is increased to the new version number, and the approximate release date is updated to be approximately what it will be when the release is made. If the release process is protracted over many days due to the testing, and any subsequent changes they require, then the date may be modified later.

If the last version was 1.3.6:

  • Find all 1.3.6 references and replace them with the new version 1.3.7.

  • Find all 1-3-6 references. These will be in links to the release article for the previous version. The link should be replaced with the link to the new article.

Writing release notes

There are two places that changes are documented in the source code. The first is a HTML-based summary that is accessible from the splash screen that ElectrumSV shows when it starts up. The second is the text-based formal RELEASE-NOTES file in the top level of the source code.

The HTML-based summary is intended to be a list of user focused descriptions of the main changes in the release. It lists the same changes as those chosen for the release article.

The RELEASE-NOTES file is intended to be developer oriented, and should attempt to list all the changes made and included in the release.

Pre-build testing

There are two different kinds of pre-build testing, both manual and automatic. The manual tests are primarily those which involve a user checking the user interface works as it should. The automatic tests ensure the code is correct as it is possible for such a tool to detect, and that when asked to perform processes the outcomes of those processes are as they should be.

User interface testing

There is a checklist of common use cases for ElectrumSV that the user interface is manually stepped through. New accounts are created, keys and seeds are imported, invoices are paid, hardware wallets are plugged in and out and most if not all of the menu options are used in order to ensure they still work.

Note

TODO: Reference manual user interface testing documents.

As bugs, problems or small aspects that can be improved are identified, they are fixed and the relevant user interfaces are retested. Along these lines, if intuitively something does not quite seem like it is working, time is spent to work out why.

Code analysis

As a part of normal development, before code changes are committed to the Github source code repository, developers are expected to run code quality tools. If they push the changes to Github and they have made changes that do not meet code quality standards, then the CI process will do those same checks and error. The changes made to both prepare the release and fix any problems observed in the user interface should be tested by the developer.

mypy

Python is a programming language with optional typing. For users who choose to use typing, this tool can then try and work out if the code that uses those types is buggy or incorrect.

Running mypy on Windows, Linux or MacOS:

mypy --config-file mypy.ini --python-version 3.7
pylint

This tool checks for general code correctness and common errors, and warns the developer if it finds any.

Running pylint on Windows, Linux or MacOS:

pylint --rcfile=.pylintrc electrum-sv electrumsv
Unit testing

The existing collection of unit tests ensure that a range of processes work correctly. This includes how the code handles different kinds of accounts, migration of wallets from older versions to newer versions, old Electrum seed words, new Electrum seed words, BIP39 seed words, different key types and so on. Running these against lower level changes can often help detect regressions or oversights made in implementing those changes.

Running the unit tests on Windows:

pytest electrumsv\tests

Running the unit tests on Linux or MacOS:

pytest electrumsv/tests

Building the release

The continuous integration (CI) service is hooked up to Github. Every time a set of changes are pushed to Github it automatically triggers the CI to test and build those changes. Every build results in what are called a set of artifacts, which are the executables and archives produced as a result of that build. If the developer adds a Git tag structured in a way to designate a release version to the changes they push, then this modifies the build process and produces an official versioned set of build artifacts.

Tagging the latest code as a potential stable release of a 1.3.7 version:

git tag sv-1.3.7

The developer than pushes both the latest code and the tag to Github, both separately, and in that order:

git push
git push --tags

A build is only triggered if unpushed code changes are pushed. And the build only looks for the release tag at the start. So the developer needs to push unpushed code changes, and then the new release tag in quick succession.

Build errors

The build runs all the tests that the developer should run before they push the final changes. If they fail, or their development tools are out of date, this might mean that either the developer did not run the tests correctly or that the developer needs to update their tools.

Recapping the automated tests employed:

  • The unit tests.

  • The functional tests.

  • Pylint for style and correctness checking.

  • Mypy for type checking.

If there are build errors or the build needs to be rerun, the developer needs to delete the tag and recreate it, and push a new tag with additional code changes to trigger a new build.

Deleting the local tag for a 1.3.7 release:

git tag --delete sv-1.3.7

Deleting the remote tag for a 1.3.7 release:

git push origin --delete sv-1.3.7
Testing the build

Once a successful candidate build has been made, the build artifacts are downloaded. One artifact is deleted, the Windows installer which is named with the -setup.exe suffix. At this time we do not support this or test it, and in the longer term we will provide this in the form of a Windows Store application.

The build testing is not extensive. If a build executable runs and the wallet user interface appears, then all testing of both functionality and user interface within the pre-build testing will represent how the build behaves.

Linux

There are no Linux builds at this time, so there is no need for testing at this stage.

Note

If a member of the community creates an AppImage build process that is of sufficient quality, we would be willing to help them maintain it and use it in producing official Linux builds.

MacOS

The build is downloaded to a MacOS device, and run.

The following trivial steps are tested:

  1. Funds are sent to the wallet on the MacOS device.

  2. The funds are then sent back out to an external wallet.

Windows

There are two builds on Windows, a portable build and a non-portable build. A quick recap on the difference is that the portable build stores it’s data in a directory local to the portable build executable. The non-portable build stores it’s data in the user’s application data directory.

The following trivial steps are tested for the non-portable build:

  1. Funds are sent to the wallet on the MacOS device.

  2. The funds are then sent back out to an external wallet.

The non-portable build is merely started, and if the user interface appears and the wallet selection screen can be reached, it is deemed sufficient.

Deployment

There are a range of steps to doing the deployment.

Build files

The build files are currently hosted for download on Amazon S3 storage rather than on the web site. This was initially done in order to try and reduce the false positive flagging for Malware that ElectrumSV gets on Windows, because of it’s use of Pyinstaller. The process of uploading these is intended to be paranoid to ensure that the files uploaded are the actually the ones the CI process produced.

After the build artifacts are uploaded to Amazon S3 storage, they are re-downloaded and the SHA256 hash of each is compared to those that CI produced by redownloading the build hashes from CI.

Web site

Besides reflecting the latest release, another function of the web site is that it hosts a JSON file with signatures from at least one developer for the given release version and date. This is used by the update checker to alert users that there is a new release. The web site also hosts the GPG signatures from at least one developer, which need to be added before it is generated.

Update signatures

The keys used to verify that a release has been signed by a known developer are hard-coded into each build. This makes it difficult to add new signing developers, as users with older builds will lack the keys for those new developers, those builds will appear illegitimate. It is probably a good idea for the process to change sooner rather than later to prepare for working around this.

One or more of the developers can sign to announce the release of the build, and each should do the following:

  1. Take the release version which might be 1.3.7.

  2. Take the release date which might be 2020-10-08T20:00:00.000000+13:00.

  3. Combine them which in this case will result in 1.3.72020-10-08T20:00:00.000000+13:00.

  4. Go into the signing wallet and select the signing key.

  5. Select the Sign/verify message menu.

  6. Enter the combined text.

  7. Click the Sign button and enter the wallet password.

  8. Copy the signature and place in the release.json file.

The existing release.json file is included in the web site generation content, and should be updated and it will automatically be included in the generated web site.

GPG signatures

In addition to hashes proving the integrity of downloaded build files, there are also GPG signatures that indicate who they came from. The public keys of the developers who might sign the build files are in Github much like the SHA256 hashes for each build file.

A sub-directory should be made within the download web site content directory for the release version, and the GPG signatures for each new build file placed in there.

Generation

With GPG signatures and release version signatures in place, and also updated for the new version and build files, the final web site can be generated and put in place on the ElectrumSV web host. The generation instructions documented in the web site directory. Assuming that the developer has already been generating the web site in the past, the following commands are all they need to do one final generation.

cd docs
cd website
pelican -s pelicanconf.py

Standard deployment steps need to be followed and the new uploaded html directory needs to match the existing one in the following ways:

  1. The same owner using chown -R.

  2. The same permissions using chmod -R.

Documentation

The documentation is hosted on the Read the Docs service. As changes are pushed to the Github repository, Read the Docs is notified and they fetch the changes and trigger an update of the documentation. This mostly benefits users being able to view development documentation. The deployed documentation for a given release cannot change any time post-release development changes are made.

After the tag for the release changes is pushed to Github, a developer needs to add it to the list of tags that Read the Docs is hosting documentation for. And then they need to make it the default tag so that the documentation URL electrumsv.readthedocs.io goes there by default.

Github

At this point the documentation, the web site, and almost all other changes should be present in Github. The one thing that may be missing is the SHA256 hashes for the build files, which need to be added to the file build-hashes.txt in the source code, and pushed as well. Beyond that they need to be merged into the master branch, which is the place we recommend users go to find them.

Github releases

Github has it’s own system for projects to make releases, and we do use that, but we do not use it to release build files. It’s primary used to formally designate the release tag as a new release, and associate it with a list of the changes in the release. The changes listed there are taken directly from the build-hashes.txt file.

Release article publication

This should just be a matter of applying any final polish to the already prepared release article and pressing whatever resembles the Publish button.

Announcements

The link to the release article should be posted to the following places with some additional decorative text.

  • Twitter.

  • The Metanet.ICU slack.

  • The Atlantistic Unwriter slack.

  • Anywhere else.

Note

TODO: Guidelines to how we write the standard decorative text should be added here.

The release checklist

It is not realistic for developers to read this document when they want to make a release and step through the description of the process. Instead, they should refer to the following checklist and where necessary refer to the description of the process for context and further details.

Note

TODO: Formalise the above as a list of concrete steps.

Indices and tables