mirror of
https://github.com/muun/recovery.git
synced 2025-11-10 05:59:44 -05:00
Release v2.2.0
This commit is contained in:
@@ -55,12 +55,30 @@ type ServerVersionResponse struct {
|
||||
Result []string `json:"result"`
|
||||
}
|
||||
|
||||
// ServerFeaturesResponse models the structure of a `server.features` response.
|
||||
type ServerFeaturesResponse struct {
|
||||
ID int `json:"id"`
|
||||
Result ServerFeatures `json:"result"`
|
||||
}
|
||||
|
||||
// ServerPeersResponse models the structure (or lack thereof) of a `server.peers.subscribe` response
|
||||
type ServerPeersResponse struct {
|
||||
ID int `json:"id"`
|
||||
Result []interface{} `json:"result"`
|
||||
}
|
||||
|
||||
// ListUnspentResponse models a `blockchain.scripthash.listunspent` response.
|
||||
type ListUnspentResponse struct {
|
||||
ID int `json:"id"`
|
||||
Result []UnspentRef `json:"result"`
|
||||
}
|
||||
|
||||
// GetTransactionResponse models the structure of a `blockchain.transaction.get` response.
|
||||
type GetTransactionResponse struct {
|
||||
ID int `json:"id"`
|
||||
Result string `json:"result"`
|
||||
}
|
||||
|
||||
// BroadcastResponse models the structure of a `blockchain.transaction.broadcast` response.
|
||||
type BroadcastResponse struct {
|
||||
ID int `json:"id"`
|
||||
@@ -75,6 +93,17 @@ type UnspentRef struct {
|
||||
Height int `json:"height"`
|
||||
}
|
||||
|
||||
// ServerFeatures contains the relevant information from `ServerFeatures` results.
|
||||
type ServerFeatures struct {
|
||||
ID int `json:"id"`
|
||||
GenesisHash string `json:"genesis_hash"`
|
||||
HashFunction string `json:"hash_function"`
|
||||
ServerVersion string `json:"server_version"`
|
||||
ProcotolMin string `json:"protocol_min"`
|
||||
ProtocolMax string `json:"protocol_max"`
|
||||
Pruning int `json:"pruning"`
|
||||
}
|
||||
|
||||
// Param is a convenience type that models an item in the `Params` array of an Request.
|
||||
type Param = interface{}
|
||||
|
||||
@@ -157,6 +186,62 @@ func (c *Client) ServerVersion() ([]string, error) {
|
||||
return response.Result, nil
|
||||
}
|
||||
|
||||
// ServerFeatures calls the `server.features` method and returns the relevant part of the result.
|
||||
func (c *Client) ServerFeatures() (*ServerFeatures, error) {
|
||||
request := Request{
|
||||
Method: "server.features",
|
||||
Params: []Param{},
|
||||
}
|
||||
|
||||
var response ServerFeaturesResponse
|
||||
|
||||
err := c.call(&request, &response)
|
||||
if err != nil {
|
||||
return nil, c.log.Errorf("ServerFeatures failed: %w", err)
|
||||
}
|
||||
|
||||
return &response.Result, nil
|
||||
}
|
||||
|
||||
// ServerPeers calls the `server.peers.subscribe` method and returns a list of server addresses.
|
||||
func (c *Client) ServerPeers() ([]string, error) {
|
||||
res, err := c.rawServerPeers()
|
||||
if err != nil {
|
||||
return nil, err // note that, besides I/O errors, some servers close the socket on this request
|
||||
}
|
||||
|
||||
var peers []string
|
||||
|
||||
for _, entry := range res {
|
||||
// Get ready for some hot casting action. Not for the faint of heart.
|
||||
addr := entry.([]interface{})[1].(string)
|
||||
port := entry.([]interface{})[2].([]interface{})[1].(string)[1:]
|
||||
|
||||
peers = append(peers, addr+":"+port)
|
||||
}
|
||||
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
// rawServerPeers calls the `server.peers.subscribe` method and returns this monstrosity:
|
||||
// [ "<ip>", "<domain>", ["<version>", "s<SSL port>", "t<TLS port>"] ]
|
||||
// Ports can be in any order, or absent if the protocol is not supported
|
||||
func (c *Client) rawServerPeers() ([]interface{}, error) {
|
||||
request := Request{
|
||||
Method: "server.peers.subscribe",
|
||||
Params: []Param{},
|
||||
}
|
||||
|
||||
var response ServerPeersResponse
|
||||
|
||||
err := c.call(&request, &response)
|
||||
if err != nil {
|
||||
return nil, c.log.Errorf("rawServerPeers failed: %w", err)
|
||||
}
|
||||
|
||||
return response.Result, nil
|
||||
}
|
||||
|
||||
// Broadcast calls the `blockchain.transaction.broadcast` endpoint and returns the transaction hash.
|
||||
func (c *Client) Broadcast(rawTx string) (string, error) {
|
||||
request := Request{
|
||||
@@ -174,6 +259,23 @@ func (c *Client) Broadcast(rawTx string) (string, error) {
|
||||
return response.Result, nil
|
||||
}
|
||||
|
||||
// GetTransaction calls the `blockchain.transaction.get` endpoint and returns the transaction hex.
|
||||
func (c *Client) GetTransaction(txID string) (string, error) {
|
||||
request := Request{
|
||||
Method: "blockchain.transaction.get",
|
||||
Params: []Param{txID},
|
||||
}
|
||||
|
||||
var response GetTransactionResponse
|
||||
|
||||
err := c.call(&request, &response)
|
||||
if err != nil {
|
||||
return "", c.log.Errorf("GetTransaction failed: %w", err)
|
||||
}
|
||||
|
||||
return response.Result, nil
|
||||
}
|
||||
|
||||
// ListUnspent calls `blockchain.scripthash.listunspent` and returns the UTXO results.
|
||||
func (c *Client) ListUnspent(indexHash string) ([]UnspentRef, error) {
|
||||
request := Request{
|
||||
|
||||
98
electrum/servers.go
Normal file
98
electrum/servers.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package electrum
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
// ServerProvider manages a rotating server list, from which callers can pull server addresses.
|
||||
type ServerProvider struct {
|
||||
nextIndex int32
|
||||
}
|
||||
|
||||
// NewServerProvider returns an initialized ServerProvider.
|
||||
func NewServerProvider() *ServerProvider {
|
||||
return &ServerProvider{-1}
|
||||
}
|
||||
|
||||
// NextServer returns an address from the rotating list. It's thread-safe.
|
||||
func (p *ServerProvider) NextServer() string {
|
||||
index := int(atomic.AddInt32(&p.nextIndex, 1))
|
||||
return PublicServers[index%len(PublicServers)]
|
||||
}
|
||||
|
||||
// PublicServers list.
|
||||
//
|
||||
// This list was taken from Electrum repositories, keeping TLS servers and excluding onion URIs.
|
||||
// It was then sorted into sections using the `cmd/survey` program, to prioritize the more reliable
|
||||
// servers with batch support.
|
||||
//
|
||||
// See https://github.com/spesmilo/electrum/blob/master/electrum/servers.json
|
||||
// See https://github.com/kyuupichan/electrumx/blob/master/electrumx/lib/coins.py
|
||||
// See `cmd/survey/main.go`
|
||||
//
|
||||
var PublicServers = []string{
|
||||
// With batch support:
|
||||
"electrum.hsmiths.com:50002",
|
||||
"E-X.not.fyi:50002",
|
||||
"VPS.hsmiths.com:50002",
|
||||
"btc.cihar.com:50002",
|
||||
"e.keff.org:50002",
|
||||
"electrum.qtornado.com:50002",
|
||||
"electrum.emzy.de:50002",
|
||||
"tardis.bauerj.eu:50002",
|
||||
"electrum.hodlister.co:50002",
|
||||
"electrum3.hodlister.co:50002",
|
||||
"electrum5.hodlister.co:50002",
|
||||
"fortress.qtornado.com:443",
|
||||
"electrumx.erbium.eu:50002",
|
||||
"bitcoin.lukechilds.co:50002",
|
||||
"electrum.bitkoins.nl:50512",
|
||||
|
||||
// Without batch support:
|
||||
"electrum.aantonop.com:50002",
|
||||
"electrum.blockstream.info:50002",
|
||||
"blockstream.info:700",
|
||||
|
||||
// Unclassified:
|
||||
"81-7-10-251.blue.kundencontroller.de:50002",
|
||||
"b.ooze.cc:50002",
|
||||
"bitcoin.corgi.party:50002",
|
||||
"bitcoins.sk:50002",
|
||||
"btc.xskyx.net:50002",
|
||||
"electrum.jochen-hoenicke.de:50005",
|
||||
"dragon085.startdedicated.de:50002",
|
||||
"e-1.claudioboxx.com:50002",
|
||||
"electrum-server.ninja:50002",
|
||||
"electrum-unlimited.criptolayer.net:50002",
|
||||
"electrum.eff.ro:50002",
|
||||
"electrum.festivaldelhumor.org:50002",
|
||||
"electrum.leblancnet.us:50002",
|
||||
"electrum.mindspot.org:50002",
|
||||
"electrum.taborsky.cz:50002",
|
||||
"electrum.villocq.com:50002",
|
||||
"electrum2.eff.ro:50002",
|
||||
"electrum2.villocq.com:50002",
|
||||
"electrumx.bot.nu:50002",
|
||||
"electrumx.ddns.net:50002",
|
||||
"electrumx.ftp.sh:50002",
|
||||
"electrumx.soon.it:50002",
|
||||
"elx01.knas.systems:50002",
|
||||
"fedaykin.goip.de:50002",
|
||||
"fn.48.org:50002",
|
||||
"ndnd.selfhost.eu:50002",
|
||||
"orannis.com:50002",
|
||||
"rbx.curalle.ovh:50002",
|
||||
"technetium.network:50002",
|
||||
"tomscryptos.com:50002",
|
||||
"ulrichard.ch:50002",
|
||||
"vmd27610.contaboserver.net:50002",
|
||||
"vmd30612.contaboserver.net:50002",
|
||||
"xray587.startdedicated.de:50002",
|
||||
"yuio.top:50002",
|
||||
"bitcoin.dragon.zone:50004",
|
||||
"ecdsa.net:110",
|
||||
"btc.usebsv.com:50006",
|
||||
"e2.keff.org:50002",
|
||||
"electrumx.electricnewyear.net:50002",
|
||||
"green-gold.westeurope.cloudapp.azure.com:56002",
|
||||
"electrumx-core.1209k.com:50002",
|
||||
"bitcoin.aranguren.org:50002",
|
||||
}
|
||||
Reference in New Issue
Block a user