electrum

package module
v0.5.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 5, 2024 License: MIT Imports: 16 Imported by: 0

README

Electrum Client

Build Status GoDoc Version Software License Go Report Card

Provides a pure Go electrum protocol client implementation.

Features include:

  • Simple to use
  • Subscriptions are managed via channels and context
  • Full TCP and TSL support
  • Safe for concurrent execution

Example

// Start a new client instance
client, _ := electrum.New(&electrum.Options{
  Address:   "node.xbt.eu:50002",
  KeepAlive: true,
})

// Execute synchronous operation
version, _ := client.ServerVersion()

// Start a subscription, will terminate automatically after 30 seconds
ctx, cancel := context.WithTimeout(context.Background(), 30 * time.Second)
defer cancel()
headers, _ := client.NotifyBlockHeaders(ctx)
for header := range headers {
  // Use header
}

// Finish client execution
client.Close()

Documentation

Overview

Package electrum provides an Electrum protocol client implementation.

The client supports two kind of operations, synchronous and asynchronous; for simplicity must methods are exported as sync operations and only long running methods, i.e. subscriptions, are exported as asynchronous.

Subscriptions take a context object that allows the client to cancel/close an instance at any given time; subscriptions also returned a channel for data transfer, the channel will be automatically closed by the client instance when the subscription is terminated.

The client supports TCP and TSL connections.

Creating a Client

First start a new client instance

client, _ := electrum.New(&electrum.Options{
  Address:   "node.xbt.eu:50002",
  KeepAlive: true,
})

Synchronous Operations

Execute operations as regular methods

version, _ := client.ServerVersion()

Subscriptions

Get notifications using regular channels and context

ctx, cancel := context.WithTimeout(context.Background(), 30 * time.Second)
defer cancel()
headers, _ := client.NotifyBlockHeaders(ctx)
  for header := range headers {
  // Use header
}

Terminating a Client

When done with the client instance free-up resources and terminate network communications

client.Close();

Protocol specification is available at: http://docs.electrum.org/en/latest/protocol.html

Index

Examples

Constants

View Source
const (
	// Version flag for the library
	Version = "0.5.4"

	// Protocol tags
	Protocol10   = "1.0"
	Protocol11   = "1.1"
	Protocol12   = "1.2"
	Protocol14   = "1.4"
	Protocol14_2 = "1.4.2"

	BitcoinBase = 1e8
)

Variables

View Source
var (
	ErrDeprecatedMethod  = errors.New("DEPRECATED_METHOD")
	ErrUnavailableMethod = errors.New("UNAVAILABLE_METHOD")
	ErrRejectedTx        = errors.New("REJECTED_TRANSACTION")
	ErrUnreachableHost   = errors.New("UNREACHABLE_HOST")
)

Common errors

Functions

func FindAddressFunc added in v0.5.3

func FindAddressFunc[E any](
	address string,
	inouts []E,
	fnAddr func(elem E, index int) bool,
)

find address in vin and vout and call fn

func GetAddressFromVout

func GetAddressFromVout(vout *Vout) string

func Round8 added in v0.5.3

func Round8(f float64) float64

round to 8 decimal places

Types

type Balance

type Balance struct {
	Confirmed   int64 `json:"confirmed"`
	Unconfirmed int64 `json:"unconfirmed"`
}

Balance show the funds available to an address, both confirmed and unconfirmed

type BlockHanders

type BlockHanders struct {
	Count   uint32   `json:"count"`
	Headers string   `json:"hex"`
	Max     uint32   `json:"max"`
	Branch  []string `json:"branch,omitempty"`
	Root    string   `json:"root,omitempty"`
}

type BlockHeader

type BlockHeader struct {
	Branch []string `json:"branch"`
	Header string   `json:"header"`
	Root   string   `json:"root"`
}

BlockHeader display summarized details about an existing block in the chain

type Client

type Client struct {
	// Address of the remote server to use for communication
	Address string

	// Version of the client
	Version string

	// Protocol version preferred by the client instance
	Protocol string

	sync.Mutex
	// contains filtered or unexported fields
}

Client defines the protocol client instance structure and interface

func New

func New(options *Options) (*Client, error)

New will create and start processing on a new client instance

func (*Client) BlockChunk deprecated

func (c *Client) BlockChunk(index int) (interface{}, error)

BlockChunk will synchronously run a 'blockchain.block.get_chunk' operation https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain.block.get_chunk

Deprecated: Since protocol 1.2 https://electrumx.readthedocs.io/en/latest/protocol-changes.html#version-1-2

func (*Client) BlockHeader

func (c *Client) BlockHeader(index int) (header *BlockHeader, err error)

func (*Client) BroadcastTransaction

func (c *Client) BroadcastTransaction(hex string) (string, error)

BroadcastTransaction will synchronously run a 'blockchain.transaction.broadcast' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-broadcast

func (*Client) Close

func (c *Client) Close()

Close will finish execution and properly terminate the underlying network transport

func (*Client) EnrichTransaction

func (c *Client) EnrichTransaction(tx *VerboseTx, blockHeight int64) (*RichTx, error)

Details a transaction by adding Prevout to Vin.

Example
client, err := New(&Options{
	Address: "reports-electrumx1.triple-a.xyz:50002",
	TLS: &tls.Config{
		InsecureSkipVerify: true,
	},
	// Log: log.New(os.Stderr, "ExampleClient_EnrichVin: ", log.LstdFlags|log.Lshortfile),
})
if err != nil {
	fmt.Println(err)
	return
}
defer client.Close()
tx, err := client.GetVerboseTransaction("5bd5c43f112181786312711e505aa68a95f513cf0db9b736f52e5860666752f2")
if err != nil {
	fmt.Println(err)
	return
}
richTx, err := client.EnrichTransaction(tx, 819827)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(richTx.Vin[0].Prevout.Value, richTx.Vin[0].Prevout.ScriptPubKey.Address)
fmt.Println(richTx.Vin[590].Prevout.Value, richTx.Vin[590].Prevout.ScriptPubKey.Address)
Output:
0.0058323 3K1Jnpy5YVZjH9DCj6zmrDJ5mdsR68RjSu
0.00584077 39NoF8tEtUwmnf2MAhvtU3ouEKEEQXYJHs

func (*Client) EnrichVin added in v0.5.1

func (c *Client) EnrichVin(vins []Vin) ([]VinWithPrevout, error)
Example
client, err := New(&Options{
	Address: "reports-electrumx1.triple-a.xyz:50002",
	TLS: &tls.Config{
		InsecureSkipVerify: true,
	},
	Log: slog.New(slog.NewJSONHandler(os.Stderr, nil)),
})
if err != nil {
	fmt.Println(err)
	return
}
defer client.Close()

tx, err := client.GetVerboseTransaction("fcf4098faf20c19925f996eaef78b2c66dd6e37e1449f024823f6fd83454e25a")
if err != nil {
	fmt.Println(err)
	return
}
vins, err := client.EnrichVin(tx.Vin)
if err != nil {
	fmt.Println(err)
	return
}

fmt.Println(len(vins))
fmt.Println(vins[0].Prevout.Value, vins[0].TxID)
fmt.Println(vins[11].Prevout.Value, vins[11].TxID)
Output:
12
0.02930787 7aeb3f74c796b0637b4c06a8034315f698f9bc45e63eaebb4de6e8425dee4223
0.02 b832e427e4f2104f400929e0b44db4c315e1d158dfe3e90b8eac616278681366

func (*Client) EstimateFee

func (c *Client) EstimateFee(blocks int) (float64, error)

EstimateFee will synchronously run a 'blockchain.estimatefee' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-estimatefee

func (*Client) GetTransaction

func (c *Client) GetTransaction(hash string) (string, error)

GetTransaction will synchronously run a 'blockchain.transaction.get' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain.transaction.get

func (*Client) GetVerboseTransaction

func (c *Client) GetVerboseTransaction(hash string) (*VerboseTx, error)
Example
client, err := New(&Options{
	Address: testServer,
	TLS: &tls.Config{
		InsecureSkipVerify: true,
	},
})
if err != nil {
	fmt.Println(err)
	return
}
defer client.Close()
tx, err := client.GetVerboseTransaction("4f73e43b92d337da8e69417601de1476bd7577cbac901fa28dba37ce1362adb9")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Printf("%d %d\n", tx.Blocktime, len(tx.Vin))
Output:
1512206656 1

func (*Client) GetVerboseTransactionBatch added in v0.5.1

func (c *Client) GetVerboseTransactionBatch(
	hashes []string,
) ([]*VerboseTx, error)

GetVerboseTransactionBatch gets the VerboseTx from a batch of transactions.

func (*Client) NotifyAddressTransactions

func (c *Client) NotifyAddressTransactions(ctx context.Context, address string) (<-chan string, error)

NotifyAddressTransactions will setup a subscription for the method 'blockchain.address.subscribe'

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-address-subscribe

func (*Client) NotifyBlockHeaders

func (c *Client) NotifyBlockHeaders(ctx context.Context) (<-chan *BlockHeader, error)

NotifyBlockHeaders will setup a subscription for the method 'blockchain.headers.subscribe'

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-headers-subscribe

func (*Client) NotifyBlockNums deprecated

func (c *Client) NotifyBlockNums(ctx context.Context) (<-chan int, error)

NotifyBlockNums will setup a subscription for the method 'blockchain.numblocks.subscribe' https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain.numblocks.subscribe

Deprecated: Since protocol 1.0 https://electrumx.readthedocs.io/en/latest/protocol-changes.html#deprecated-methods

func (*Client) ScriptHashBalance

func (c *Client) ScriptHashBalance(scriptHash string) (*Balance, error)

ScriptHashBalanceBalance will synchronously run a 'blockchain.scripthash.get_balance' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-scripthash-get-balance

Example
client, err := New(&Options{
	Address: testServer,
	TLS: &tls.Config{
		InsecureSkipVerify: true,
	},
})
if err != nil {
	fmt.Println(err)
	return
}
defer client.Close()
// address: 13aoDNsMJ8w1EAvT8LkH8WnAYrygBAUUF1
balance, err := client.ScriptHashBalance("9e973caf3b602db193b420497a043ea99225976eff5a33037a107ac291882c70")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(balance.Confirmed)
Output:
582991

func (*Client) ScriptHashHistory

func (c *Client) ScriptHashHistory(scriptHash string) ([]Tx, error)

ScriptHashHistory will synchronously run a 'blockchain.scripthash.get_history' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-scripthash-get-history

Example
client, err := New(&Options{
	Address: testServer,
	TLS: &tls.Config{
		InsecureSkipVerify: true,
	},
})
if err != nil {
	fmt.Println(err)
	return
}
defer client.Close()
// address: 13aoDNsMJ8w1EAvT8LkH8WnAYrygBAUUF1
history, err := client.ScriptHashHistory("9e973caf3b602db193b420497a043ea99225976eff5a33037a107ac291882c70")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println((history)[0].Height)
Output:
768424

func (*Client) ScriptHashListUnspent

func (c *Client) ScriptHashListUnspent(scripthash string) ([]UnspentTx, error)

ScriptHashListUnspent will synchronously run a 'blockchain.scripthash.listunspent' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-scripthash-listunspent

func (*Client) ScriptHashMempool

func (c *Client) ScriptHashMempool(scripthash string) ([]MempoolTx, error)

ScriptHashMempool will synchronously run a 'blockchain.scripthash.get_mempool' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-scripthash-get-mempool

func (*Client) ServerBanner

func (c *Client) ServerBanner() (string, error)

ServerBanner will synchronously run a 'server.banner' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-banner

func (*Client) ServerDonationAddress

func (c *Client) ServerDonationAddress() (string, error)

ServerDonationAddress will synchronously run a 'server.donation_address' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-donation-address

Example
client, err := New(&Options{
	Address: testServer,
	TLS: &tls.Config{
		InsecureSkipVerify: true,
	},
})
if err != nil {
	fmt.Println(err)
	return
}
defer client.Close()
addr, err := client.ServerDonationAddress()
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(addr)
Output:
36UgQmHjUainV6B7HV58vmV3gAc1w3Rurt

func (*Client) ServerFeatures

func (c *Client) ServerFeatures() (*ServerInfo, error)

ServerFeatures returns a list of features and services supported by the server

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-donation-address

func (*Client) ServerPeers

func (c *Client) ServerPeers() (peers []*Peer, err error)

ServerPeers returns a list of peer servers

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-peers-subscribe

func (*Client) ServerPing

func (c *Client) ServerPing() error

ServerPing will send a ping message to the server to ensure it is responding, and to keep the session alive. The server may disconnect clients that have sent no requests for roughly 10 minutes.

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-ping

func (*Client) ServerVersion

func (c *Client) ServerVersion() (*VersionInfo, error)

ServerVersion will synchronously run a 'server.version' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#server-version

Example
client, err := New(&Options{
	Address: testServer,
	TLS: &tls.Config{
		InsecureSkipVerify: true,
	},
})
if err != nil {
	fmt.Println(err)
	return
}
defer client.Close()
version, err := client.ServerVersion()
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(version.Software)
Output:
ElectrumX 1.16.0

func (*Client) TransactionMerkle

func (c *Client) TransactionMerkle(tx string, height int) (tm *TxMerkle, err error)

TransactionMerkle will synchronously run a 'blockchain.transaction.get_merkle' operation

https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get-merkle

func (*Client) UTXOAddress deprecated

func (c *Client) UTXOAddress(utxo string) (string, error)

UTXOAddress will synchronously run a 'blockchain.utxo.get_address' operation https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain.utxo.get_address

Deprecated: Since protocol 1.0 https://electrumx.readthedocs.io/en/latest/protocol-changes.html#deprecated-methods

type ConnectionState

type ConnectionState string

ConnectionState represents known connection state values

const (
	Ready        ConnectionState = "READY"
	Disconnected ConnectionState = "DISCONNECTED"
	Reconnecting ConnectionState = "RECONNECTING"
	Reconnected  ConnectionState = "RECONNECTED"
	Closed       ConnectionState = "CLOSED"
)

Connection state flags

type Host

type Host struct {
	SSLPort uint `json:"ssl_port"`
	TCPPort uint `json:"tcp_port"`
}

Host provides available endpoints for a given server

type MempoolTx added in v0.5.1

type MempoolTx struct {
	Tx
	Fee uint64 `json:"fee"`
}

type Options

type Options struct {
	// Address of the server to use for network communications
	Address string

	// Version advertised by the client instance
	Version string

	// Protocol version preferred by the client instance
	Protocol string

	// If set to true, will enable the client to continuously dispatch
	// a 'server.version' operation every 60 seconds
	KeepAlive bool

	// Agent identifier that will be transmitted to the server when required;
	// will be concatenated with the client version
	Agent string

	// If provided, will be used to setup a secure network connection with the server
	TLS *tls.Config

	// If provided, will be used as logging sink
	Log *slog.Logger

	// Timeout for network operations
	Timeout time.Duration

	// The maximum number of transactions to fetch in a single batch
	MaxBatchSize uint32
}

Options define the available configuration options

type Peer

type Peer struct {
	Address  string   `json:"address"`
	Name     string   `json:"name"`
	Features []string `json:"features"`
}

Peer provides details of a known server node

type RichTx

type RichTx struct {
	VerboseTx
	Vin          []VinWithPrevout `json:"vin"`
	InputsTotal  float64          `json:"inputs_total"`
	OutputsTotal float64          `json:"outputs_total"`
	FeeInSat     int64            `json:"fee_in_sat"`
	Height       int64            `json:"height"`
	Fee          float64          `json:"fee,omitempty"`
}

RichTx represents a transaction entry on the blockchain with VinWithPrevout

type ScriptPubKey

type ScriptPubKey struct {
	Addresses []string `json:"addresses,omitempty"`
	Address   string   `json:"address,omitempty"`
	Asm       string   `json:"asm"`
	Hex       string   `json:"hex,omitempty"`
	ReqSigs   uint32   `json:"reqSigs,omitempty"`
	Type      string   `json:"type"`
}

ScriptPubKey represents the script of that transaction output.

type ScriptSig

type ScriptSig struct {
	Asm string `json:"asm"`
	Hex string `json:"hex"`
}

ScriptSig represents the signature script for that transaction input.

type ServerInfo

type ServerInfo struct {
	// A dictionary of endpoints that this server can be reached at. Normally this will only have a
	// single entry; other entries can be used in case there are other connection routes
	Hosts map[string]*Host `json:"hosts"`

	// The hash of the genesis block, can be used to detect if a peer is connected to one serving a different network
	GenesisHash string `json:"genesis_hash"`

	// The hash function the server uses for script hashing. The client must use this function to hash
	// pay-to-scripts to produce script hashes to send to the server
	HashFunction string `json:"hash_function"`

	// A string that identifies the server software
	ServerVersion string `json:"server_version"`

	// Max supported version of the protocol
	ProtocolMax string `json:"protocol_max"`

	// Min supported version of the protocol
	ProtocolMin string `json:"protocol_min"`
}

ServerInfo provides general information about the state and capabilities of the server

type Tx

type Tx struct {
	Hash   string `json:"tx_hash"`
	Height int64  `json:"height"`
}

Tx represents a transaction entry on the blockchain

type TxCache

type TxCache struct {
	// contains filtered or unexported fields
}

func NewTxCache

func NewTxCache(db *sql.DB) (*TxCache, error)

func (*TxCache) Close

func (c *TxCache) Close() error

func (*TxCache) Load

func (c *TxCache) Load(txID string, tx any) bool

func (*TxCache) Store

func (c *TxCache) Store(txID string, tx any) error

type TxMerkle

type TxMerkle struct {
	BlockHeight float64  `json:"block_height"`
	Pos         uint64   `json:"pos"`
	Merkle      []string `json:"merkle"`
}

TxMerkle provides the merkle branch of a given transaction

type UnspentTx added in v0.5.1

type UnspentTx struct {
	Tx
	Value uint64 `json:"value"`
	Pos   uint64 `json:"tx_pos"`
}

type VerboseTx

type VerboseTx struct {
	Blockhash     string   `json:"blockhash"`
	Blocktime     uint64   `json:"blocktime"`
	Confirmations int32    `json:"confirmations"`
	Hash          string   `json:"hash"`
	Hex           string   `json:"hex"`
	Locktime      uint32   `json:"locktime"`
	Size          uint32   `json:"size"`
	Time          uint64   `json:"time"`
	TxID          string   `json:"txid"`
	Version       uint32   `json:"version"`
	Vin           []Vin    `json:"vin"`
	Vout          []Vout   `json:"vout"`
	Merkle        TxMerkle `json:"merkle,omitempty"` // For protocol v1.5 and up.
}

type VersionInfo

type VersionInfo struct {
	Software string `json:"software"`
	Protocol string `json:"protocol"`
}

VersionInfo contains the version information returned by the server

type Vin

type Vin struct {
	Coinbase  string    `json:"coinbase"`
	ScriptSig ScriptSig `json:"scriptSig"`
	Sequence  uint32    `json:"sequence"`
	TxID      string    `json:"txid"`
	Vout      uint32    `json:"vout"`
}

Vin represents the input side of a transaction.

type VinWithPrevout

type VinWithPrevout struct {
	*Vin
	Prevout *Vout `json:"prevout"`
}

type Vout

type Vout struct {
	N            uint32       `json:"n"`
	ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
	Value        float64      `json:"value"`
}

Vout represents the output side of a transaction.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL