privatebtc

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2023 License: Apache-2.0 Imports: 16 Imported by: 0

README

PrivateBTC - Bitcoin Private Network Management and Testing Tool

GitHub license

GitHub release GitHub go.mod Go version of a Go module GoDoc reference

CodeFactor Go Report Card codecov

lint-test release grype codeql

PrivateBTC offers a solution for Bitcoin enthusiasts and developers. It operates as a standalone project with a Terminal User Interface (TUI) for effortless Bitcoin Private Network management. Simultaneously, it serves as a testing tool, catering to Bitcoin applications developed in Go.

With PrivateBTC, you can easily create a Bitcoin network with multiple nodes, manage addresses, send transactions, mine blocks, and even simulate chain reorganizations programmatically.

This tool is particularly valuable for Go developers working directly with the Bitcoin protocol, allowing them to test their applications' resilience under various scenarios.

Note: The current version only supports creating Bitcoin nodes with Docker. The plan for future versions is to support other, preferably, native node clients.



Prerequisites

Before you can use this project, please ensure that you have the following prerequisites met:

  1. Docker Daemon: This project relies on Docker for containerization. Make sure you have Docker installed and the Docker daemon running on your machine. If Docker is not installed, you can download and install it from the official Docker website: Docker Installation Guide. Docker provides a convenient way to start Bitcoin nodes in isolation. You can verify that the Docker daemon is running by executing the following command in your terminal:
    docker info
    
Check environment dependencies

A subcommand is provided to check if the environment dependencies are met.

privatebtc envcheck

Installation

Download pre-built binaries

Go Install
  1. Run the go install command: This will add the privatebtc command to your $GOPATH/bin directory.
go install github.com/adrianbrad/privatebtc/cmd/privatebtc@latest
  1. Run the TUI:
privatebtc

Building from source
  1. Clone the repo:
git clone https://github.com/adrianbrad/privatebtc
  1. Build the command binary:
go build -o privatebtc ./cmd
  1. Run the TUI:
./privatebtc

Importing in your project
  1. Add this package as a dependency to your project:
go get -u github.com/adrianbrad/privatebtc
  1. Import the package in your project:
import "github.com/adrianbrad/privatebtc"

Usage

TUI

Guide
  1. Switching Focus Between Panels:

    • Use the Left and Right Arrow Keys to move focus between the following panels in sequence: Transactions -> Mempool -> Details -> Actions Output -> Nodes -> Details.
  2. Selecting an Action:

    • Once focused on the Actions panel, use the Up and Down Arrow Keys to navigate through the available items.
    • Press Enter to confirm and perform the selected action.
  3. Navigating Inside Modals:

    • If a modal (like the one labeled "Mine Blocks") appears:
      • Use the Tab key to cycle through different fields or buttons inside the modal.
      • Make your selection or input using the Enter key.
      • Press Esc to exit or dismiss the modal without making a selection or action.

Create Address

Ceate Address

In order to create a new Address, select the node you want to create the address on, by focusing on the Nodes panel and using the Up and Down Arrow Keys to navigate through the available items. After you have selected the node, move the focus on the Actions panel and select the Create Address action.

Funding and Mining

Funding and Mining

In order to fund a node, select the node you want to fund, by focusing on the Nodes panel and using the Up and Down Arrow Keys to navigate through the available items. After you have selected the node, move the focus to the Actions panel and select the Mine to Address action. A modal will appear, asking you to input the number of blocks you want to mine and the address to where to send the coinbase reward.

Send BTC

Send BTC In order to send BTC from one node to another, select the node you want to send BTC from, by focusing on the Nodes panel and using the Up and Down Arrow Keys to navigate through the available items. After you have selected the node, move the focus to the Actions panel and select the Send to address action. A modal will appear, asking you to input the address to where to send the BTC and the amount to send. In order to confirm the transaction, a new block has to be mined on the network, you can find more details about this in the Funding and Mining section.

Chain Reorg Involving Double Spend

Double Spend

To successfully execute a double spend, wherein both transactions are valid and initially mined in separate blocks before a chain reorganization resolves the conflict, follow these steps:

  1. Selection of the Node: Navigate to the Nodes panel. Use the Up and Down Arrow Keys to sift through and select the node from which you wish to initiate the double spend.

  2. Initiate a Transaction: Refer to the Send BTC section and execute the necessary steps to send a transaction.

  3. Verification Across Mempools: Confirm that other nodes have received the transaction in their mempools.

  4. Disconnect the Chosen Node: Opt for the Disconnect from network action to isolate the node.

  5. Replace the Transaction: Choose the Replace By Fee Drain To Address action. This will reroute the cumulative total of the original transaction's inputs to a different address.

  6. First Confirmation:

    • Connect to a node that's still part of the network and mine a block.
    • This will confirm the initial transaction, effectively transferring the funds.
  7. Second Confirmation:

    • Now, mine a block on the node you previously disconnected.
    • This action will validate the second transaction, reallocating the funds once again.
  8. Reconnect and Fork: Re-integrate the previously isolated node back into the network. At this point, you'll observe two chains of equal length, signaling a fork in the blockchain.

  9. Resolve the Fork:

    • Mine an additional block, either on the main network or on the previously disconnected node.
    • Depending on where you choose to mine this block, one of the two transactions will be negated, while the other remains validated. The blockchain reorganization will ensure that the longer chain is accepted, thereby resolving the double-spend attempt.

Testing Bitcoin Applications in GO
Private network with 2 nodes and address generation
package app_test

import (
  "context"
  "testing"

  "github.com/adrianbrad/privatebtc"
  "github.com/adrianbrad/privatebtc/btcsuite"
  "github.com/adrianbrad/privatebtc/docker/testcontainers"
)

func TestApp(t *testing.T) {
  pn, err := privatebtc.NewPrivateNetwork(
    &testcontainers.NodeService{},
    &btcsuite.RPCClientFactory{},
    2,
    privatebtc.WithWallet(t.Name()),
  )
  if err != nil {
    t.Fatalf("new private network error: %s", err)
  }

  t.Cleanup(func() {
    if err := pn.Close(); err != nil {
      t.Logf("close private network error: %s", err)
    }
  })

  ctx := context.TODO()

  if err := pn.Start(ctx); err != nil {
    t.Fatalf("start private network error: %s", err)
  }

  const addressLabel = "label"

  addr, err := pn.Nodes()[0].RPCClient().GetNewAddress(ctx, addressLabel)
  if err != nil {
    t.Fatalf("get new address error: %s", err)
  }

  t.Logf("new address: %s", addr)

  // actual test code here...
}


Chain reorg with double spend
package app_test

import (
  "context"
  "testing"

  "github.com/adrianbrad/privatebtc"
  "github.com/adrianbrad/privatebtc/btcsuite"
  "github.com/adrianbrad/privatebtc/docker/testcontainers"
)

func TestChainReorg(t *testing.T) {
  pn, err := privatebtc.NewPrivateNetwork(
    &testcontainers.NodeService{},
    &btcsuite.RPCClientFactory{},
    2,
    privatebtc.WithWallet(t.Name()),
  )
  if err != nil {
    t.Fatalf("new private network error: %s", err)
  }

  t.Cleanup(func() {
    if err := pn.Close(); err != nil {
      t.Logf("close private network error: %s", err)
    }
  })

  ctx := context.TODO()

  // start the private network,
  if err := pn.Start(ctx); err != nil {
    t.Fatalf("start private network error: %s", err)
  }

  const disconnectedNodeIndex = 0

  // add funds to the node that will be disconnected.
  lastBlockHash, err := pn.Nodes()[disconnectedNodeIndex].Fund(ctx)
  if err != nil {
    t.Fatalf("fund node error: %s", err)
  }

  // sync all nodes to the last block hash.
  if err := pn.Nodes().Sync(ctx, lastBlockHash); err != nil {
    t.Fatalf("sync nodes to block hash %q: %s", lastBlockHash, err)
  }

  // generate an address on the node that will be disconnected.
  disconnectedNodeAddr, err := pn.Nodes()[disconnectedNodeIndex].RPCClient().GetNewAddress(ctx, "label")
  if err != nil {
    t.Fatalf("generate node %d addr: %s", disconnectedNodeIndex, err)
  }

  // generate an address on node 1.
  node1Addr, err := pn.Nodes()[1].RPCClient().GetNewAddress(ctx, "label")
  if err != nil {
    t.Fatalf("generate node 1 addr: %s", err)
  }

  // send a tx from the disconnected node to node 1.
  txHash, err := pn.Nodes()[disconnectedNodeIndex].RPCClient().SendToAddress(ctx, node1Addr, 1)
  if err != nil {
    t.Fatalf("send to address error: %s", err)
  }

  // prepare the chain reorg
  cr, err := pn.NewChainReorgWithAssertion(disconnectedNodeIndex)
  if err != nil {
    t.Fatalf("new chain reorg error: %s", err)
  }

  // disconnect the specified disconnected node.
  if _, err := cr.DisconnectNode(ctx); err != nil {
    t.Fatalf("disconnect node error: %s", err)
  }

  // replace the transaction with a transaction that drains the funds to the specified address.
  if _, err := privatebtc.ReplaceTransactionDrainToAddress(
    ctx,
    pn.Nodes()[disconnectedNodeIndex].RPCClient(),
    txHash,
    disconnectedNodeAddr,
  ); err != nil {
    t.Fatalf("replace transaction drain to address error: %s", err)
  }

  // at this point we have to transactions that spend the same funds, one of them will be dropped.
  // blocks will be mined on the network and on the disconnected node, as long as the nodes are
  // the longest chain will be selected as the main chain.

  const netNumBlocks = 1

  // mine 2 blocks on the network.
  if _, err := cr.MineBlocksOnNetwork(ctx, netNumBlocks); err != nil {
    t.Fatalf("mine blocks on network error: %s", err)
  }

  const discNumBlocks = netNumBlocks + 1

  // mine 2 blocks on the disconnected node.
  if _, err := cr.MineBlocksOnDisconnectedNode(ctx, discNumBlocks); err != nil {
    t.Fatalf("mine blocks on disconnected node error: %s", err)
  }

  // reconnect the specified disconnected node.
  if err := cr.ReconnectNode(ctx); err != nil {
    t.Fatalf("reconnect node error: %s", err)
  }

  // as soon as the node is reconnected, it will start syncing with the network.
  // the network will select the longest chain as the main chain, with the longest
  // chain being the one on the disconnected node, the transaction that send funds
  // to node 1 will be dropped, and the transaction that replaced it, sending funds
  // back to the disconnected block will be included in the chain.
}

Known Issues

PrivateBTC fails if

  • you do not have docker installed on your machine.

Documentation

Overview

Package privatebtc handles the creation of a Bitcoin private network using Docker.

The package defines a NodeService interface that can be implemented to use different Node Handlers. The package also defines a RPCClientFactory interface that can be implemented to use different Go Bitcoin RPC Clients. A chain reorganisation manager is implemented, it streamlines the process of creating chain reorganisations.

Index

Constants

View Source
const (
	RPCRegtestDefaultPort = "18443"
	P2PRegtestDefaultPort = "18444"
)

Default Bitcoin Core ports for regtest.

Variables

View Source
var (
	// ErrCannotConnectToDockerAPI is returned when the Docker Engine API cannot be reached.
	ErrCannotConnectToDockerAPI = errors.New("cannot connect to Docker Engine API")
	// ErrPeerNotFound is returned when a peer is not found in a node's peer info response.
	ErrPeerNotFound = errors.New("peer not found in node peer info response")
	// ErrChainReorgMustDisconnectNodeFirst is returned whenever a chain reorg action is attempted
	// without first disconnecting a node from the network.
	// nolint: revive // line too long
	ErrChainReorgMustDisconnectNodeFirst = errors.New("chain reorg: must disconnect node first")
	// ErrTimeoutAndChainsAreNotSynced is returned when a timeout occurs and the
	// chains are not synced.
	ErrTimeoutAndChainsAreNotSynced = errors.New("timeout and chains are not synced")
	// ErrChainsShouldNotBeSynced is returned when the chains should not be synced.
	ErrChainsShouldNotBeSynced = errors.New("chains should not be synced")
	// ErrTxNotFoundInMempool is returned when a transaction is not found in the mempool.
	ErrTxNotFoundInMempool = errors.New("tx not found in mempool")
	// ErrTxFoundInMempool is returned when a transaction is unexpectedly found in the mempool.
	ErrTxFoundInMempool = errors.New("tx found in mempool")
	// ErrNodeIndexOutOfRange is returned when a node index is out of range.
	ErrNodeIndexOutOfRange = errors.New("node index out of range")
)

exported errors.

Functions

func ReplaceTransactionDrainToAddress

func ReplaceTransactionDrainToAddress(
	ctx context.Context,
	client RPCClient,
	txID string,
	address string,
) (string, error)

ReplaceTransactionDrainToAddress performs a replace by fee(RBF) for the given transaction id. The new transaction will drain the inputs of the old transaction to the given address while increasing the fee by 100%.

Types

type Balance

type Balance struct {
	Trusted  float64
	Pending  float64
	Immature float64
}

Balance is a balance of a node.

type ChainReorg

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

ChainReorg represents a chain reorg manager.

func (*ChainReorg) DisconnectNode

func (c *ChainReorg) DisconnectNode(ctx context.Context) (Node, error)

DisconnectNode disconnects a node from the network.

func (*ChainReorg) MineBlocksOnDisconnectedNode

func (c *ChainReorg) MineBlocksOnDisconnectedNode(
	ctx context.Context,
	numBlocks int64,
) ([]string, error)

MineBlocksOnDisconnectedNode mines blocks on the disconnected node.

func (*ChainReorg) MineBlocksOnNetwork

func (c *ChainReorg) MineBlocksOnNetwork(ctx context.Context, numBlocks int64) ([]string, error)

MineBlocksOnNetwork mines blocks on the network.

func (*ChainReorg) ReconnectNode

func (c *ChainReorg) ReconnectNode(ctx context.Context) error

ReconnectNode reconnects the disconnected node to the network.

func (*ChainReorg) SendTransactionOnDisconnectedNode

func (c *ChainReorg) SendTransactionOnDisconnectedNode(
	ctx context.Context,
	receiverAddress string,
	amount float64,
) (string, error)

SendTransactionOnDisconnectedNode sends a transaction on the disconnected node.

func (*ChainReorg) SendTransactionOnNetwork

func (c *ChainReorg) SendTransactionOnNetwork(
	ctx context.Context,
	receiverAddress string,
	amount float64,
) (string, error)

SendTransactionOnNetwork sends a transaction on the network.

type ChainReorgManager

type ChainReorgManager interface {
	DisconnectNode(ctx context.Context) (Node, error)
	SendTransactionOnNetwork(
		ctx context.Context,
		receiverAddress string,
		amount float64,
	) (string, error)
	SendTransactionOnDisconnectedNode(ctx context.Context, receiverAddress string, amount float64) (string, error)
	MineBlocksOnNetwork(ctx context.Context, numBlocks int64) ([]string, error)
	MineBlocksOnDisconnectedNode(ctx context.Context, numBlocks int64) ([]string, error)
	ReconnectNode(ctx context.Context) error
}

ChainReorgManager defines methods for handling a chain reorg. nolint: revive

type ChainReorgWithAssertion

type ChainReorgWithAssertion struct {
	*ChainReorg
}

ChainReorgWithAssertion represents a chain reorg manager with assertion.

func (*ChainReorgWithAssertion) DisconnectNode

func (c *ChainReorgWithAssertion) DisconnectNode(ctx context.Context) (Node, error)

DisconnectNode disconnects a node from the network. It is expected that the node will have 0 peers after disconnecting.

func (*ChainReorgWithAssertion) MineBlocksOnDisconnectedNode

func (c *ChainReorgWithAssertion) MineBlocksOnDisconnectedNode(
	ctx context.Context,
	numBlocks int64,
) ([]string, error)

MineBlocksOnDisconnectedNode mines blocks on the disconnected node. It is expected that the network nodes do not will not see the new blocks.

func (*ChainReorgWithAssertion) MineBlocksOnNetwork

func (c *ChainReorgWithAssertion) MineBlocksOnNetwork(
	ctx context.Context,
	numBlocks int64,
) ([]string, error)

MineBlocksOnNetwork mines blocks on the network. It is expected that the disconnected node will not see the new blocks.

func (*ChainReorgWithAssertion) ReconnectNode

func (c *ChainReorgWithAssertion) ReconnectNode(ctx context.Context) error

ReconnectNode reconnects the disconnected node to the network. It is expected that the disconnected node will reorg to the network chain.

func (*ChainReorgWithAssertion) SendTransactionOnDisconnectedNode

func (c *ChainReorgWithAssertion) SendTransactionOnDisconnectedNode(
	ctx context.Context,
	receiverAddress string,
	amount float64,
) (string, error)

SendTransactionOnDisconnectedNode sends a transaction on the disconnected node. It is expected that the transaction is not in any network node mempool.

func (*ChainReorgWithAssertion) SendTransactionOnNetwork

func (c *ChainReorgWithAssertion) SendTransactionOnNetwork(
	ctx context.Context,
	receiverAddress string,
	amount float64,
) (string, error)

SendTransactionOnNetwork sends a transaction on the network. It is expected that the transaction is in every node mempool except the disconnected node.

type CreateNodeRequest

type CreateNodeRequest struct {
	RPCAuth     string
	FallbackFee float64
}

CreateNodeRequest is used to create a node.

type Node

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

Node represents a node in the private network. It contains an RPC client and a Node Handler.

func (Node) ConnectToNetwork

func (n Node) ConnectToNetwork(ctx context.Context) error

ConnectToNetwork connects the node to the network (the other nodes).

func (Node) DisconnectFromNetwork

func (n Node) DisconnectFromNetwork(ctx context.Context) error

DisconnectFromNetwork disconnects the node from the network (the other nodes).

func (Node) Fund

func (n Node) Fund(ctx context.Context) (string, error)

Fund is a helper function for funding a node. It generates a new address to the block and mines 101 blocks to it, returning the hash of the last block that was mined This method will fund the node wallet with 50 BTC.

func (Node) ID

func (n Node) ID() int

ID returns the ID of the node.

func (Node) IsTransactionInMempool

func (n Node) IsTransactionInMempool(ctx context.Context, txHash string) (bool, error)

IsTransactionInMempool checks if a transaction is in the mempool of the node.

func (Node) Name

func (n Node) Name() string

Name returns the Name of the node.

func (Node) NodeHandler

func (n Node) NodeHandler() NodeHandler

NodeHandler returns the nodeHandler of the node.

func (Node) RPCClient

func (n Node) RPCClient() RPCClient

RPCClient returns the RPC client of the node.

type NodeHandler

type NodeHandler interface {
	io.Closer
	InternalIP() string
	HostRPCPort() string
	Name() string
}

NodeHandler represents manager for a bitcoin node.

type NodeService

type NodeService interface {
	CreateNodes(
		ctx context.Context,
		nodeRequests []CreateNodeRequest,
	) ([]NodeHandler, error)
}

NodeService is a service for creating Bitcoin Nodes.

type Nodes

type Nodes []Node

Nodes is a slice of nodes.

func (Nodes) EnsureTransactionInEveryMempool

func (nodes Nodes) EnsureTransactionInEveryMempool(
	ctx context.Context,
	txHash string,
) error

EnsureTransactionInEveryMempool ensures that a transaction is in the mempool of every node. nolint: gocognit

func (Nodes) EnsureTransactionNotInAnyMempool

func (nodes Nodes) EnsureTransactionNotInAnyMempool(ctx context.Context, txHash string) error

EnsureTransactionNotInAnyMempool ensures that transaction is not in any mempool of the nodes.

func (Nodes) Sync

func (nodes Nodes) Sync(ctx context.Context, toBlockHash string) error

Sync waits until all nodes are on the same block height. nolint: gocognit

type Option

type Option interface {
	// contains filtered or unexported methods
}

An Option configures a parameter for the Bitcoin Private Network. The functional options are implemented following uber guidelines. https://github.com/uber-go/guide/blob/master/style.md#functional-options

func WithBitcoinClientVersion

func WithBitcoinClientVersion(version string) Option

WithBitcoinClientVersion configures the version of the bitcoin client to use.

func WithNodeNamePrefix

func WithNodeNamePrefix(nodeNamePrefix string) Option

WithNodeNamePrefix configures the prefix for the node names.

func WithRPCAuth

func WithRPCAuth(rpcUser, rpcPassword string) Option

WithRPCAuth configures the RPC authentication for the Bitcoin Private Network.

func WithSlogHandler

func WithSlogHandler(handler slog.Handler) Option

WithSlogHandler configures the handler for the Bitcoin Private Network.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout configures the timeout for the docker operations.

func WithWallet

func WithWallet(walletName string) Option

WithWallet configures and creates a wallet for the nodes.

type PrivateNetwork

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

PrivateNetwork is a Bitcoin private network.

func NewPrivateNetwork

func NewPrivateNetwork(
	nodeService NodeService,
	rpcClientFactory RPCClientFactory,
	nodes int,
	opts ...Option,
) (*PrivateNetwork, error)

NewPrivateNetwork creates a new private network with the given number of nodes.

func (*PrivateNetwork) Close

func (n *PrivateNetwork) Close() error

Close terminates all nodes in the private network.

func (*PrivateNetwork) NewChainReorg

func (n *PrivateNetwork) NewChainReorg(
	disconnectedNodeIndex int,
) (*ChainReorg, error)

NewChainReorg creates a new chain reorg manager.

func (*PrivateNetwork) NewChainReorgWithAssertion

func (n *PrivateNetwork) NewChainReorgWithAssertion(
	disconnectedNodeIndex int,
) (*ChainReorgWithAssertion, error)

NewChainReorgWithAssertion creates a new chain reorg manager with assertion.

func (*PrivateNetwork) Nodes

func (n *PrivateNetwork) Nodes() Nodes

Nodes returns a copy of the nodes in the private network.

func (*PrivateNetwork) Start

func (n *PrivateNetwork) Start(ctx context.Context) error

Start creates the private network nodes and connects them.

type RPCClient

type RPCClient interface {
	// SendToAddress sends the given satoshi amount to the given address.
	SendToAddress(ctx context.Context, address string, amount float64) (txHash string, _ error)

	// SendCustomTransaction sends a custom transaction with the given inputs and amounts.
	SendCustomTransaction(ctx context.Context, inputs []TransactionVin, amounts map[string]float64) (txHash string, _ error)

	// GenerateToAddress generates the given number of blocks to the given address.
	GenerateToAddress(ctx context.Context, numBlocks int64, address string) (blockHashes []string, _ error)

	// GetConnectionCount returns the number of connections to other nodes.
	GetConnectionCount(ctx context.Context) (int, error)

	// AddPeer adds the given peer to the node.
	AddPeer(ctx context.Context, peer Node) error

	// RemovePeer removes the given peer from the node.
	RemovePeer(ctx context.Context, peer Node) error

	// CreateWallet creates a new wallet with the given name.
	CreateWallet(ctx context.Context, walletName string) error

	// GetRawMempool returns all transaction ids in memory pool
	GetRawMempool(ctx context.Context) ([]string, error)

	// GetBlockCount returns the number of blocks in the longest blockchain.
	GetBlockCount(ctx context.Context) (int, error)

	// GetNewAddress returns a new address for receiving payments.
	GetNewAddress(ctx context.Context, label string) (string, error)

	// GetBalance returns the total available balance.
	// From the Bitcoin Core RPC Docs:
	// The available balance is what the wallet considers currently spendable, and is
	// thus affected by options which limit spendability such as -spendzeroconfchange.
	GetBalance(ctx context.Context) (Balance, error)

	// GetTransaction returns the transaction with the given hash.
	GetTransaction(ctx context.Context, txHash string) (*Transaction, error)

	ListAddresses(ctx context.Context) ([]string, error)

	GetBestBlockHash(ctx context.Context) (string, error)

	GetCoinbaseValue(ctx context.Context) (int64, error)
}

RPCClient is an interface for RPC clients. The methods are closely mapped to the bitcoin RPC API. nolint: interfacebloat, revive

type RPCClientFactory

type RPCClientFactory interface {
	NewRPCClient(hostRPCPort, rpcUser, rpcPass string) (RPCClient, error)
}

RPCClientFactory is an interface for RPC client factories. It is used to decouple the creation of the RPC Client from the actual implementation. We have to use the factory pattern because the RPC Clients are created dynamically for each node when the network is created.

type Transaction

type Transaction struct {
	TxID      string
	Hash      string
	BlockHash string
	Vout      []TransactionVout
	Vin       []TransactionVin
}

Transaction represents a BTC transaction.

func (Transaction) GetTransactionFee

func (tx Transaction) GetTransactionFee(totalInputs float64) float64

GetTransactionFee returns the transaction fee.

func (Transaction) TotalInputsValue

func (tx Transaction) TotalInputsValue(ctx context.Context, client RPCClient) (float64, error)

TotalInputsValue sums up the value of all inputs in the transaction by checking the value of the outputs that they spend from.

type TransactionVin

type TransactionVin struct {
	TxID string
	Vout uint32
}

TransactionVin represents a BTC transaction input.

type TransactionVout

type TransactionVout struct {
	Value        float64
	N            uint32
	ScriptPubKey struct {
		Address string
	}
}

TransactionVout represents a BTC transaction output.

type UnexpectedPeerCountError

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

UnexpectedPeerCountError is returned when a node has an unexpected number of peers.

func (*UnexpectedPeerCountError) Error

func (e *UnexpectedPeerCountError) Error() string

Directories

Path Synopsis
Package btcsuite provides implementations of the privatebtc.RPCClientFactory and privatebtc.RPCClient interfaces using the https://github.com/ory/dockertest package.
Package btcsuite provides implementations of the privatebtc.RPCClientFactory and privatebtc.RPCClient interfaces using the https://github.com/ory/dockertest package.
cmd
Package docker provides utility functions for checking the Docker environment.
Package docker provides utility functions for checking the Docker environment.
dockertest
Package dockertest provides implementations of the privatebtc.NodeService and privatebtc.NodeHandler interfaces using the https://github.com/ory/dockertest package.
Package dockertest provides implementations of the privatebtc.NodeService and privatebtc.NodeHandler interfaces using the https://github.com/ory/dockertest package.
testcontainers
Package testcontainers provides implementations of the privatebtc.NodeService and privatebtc.NodeHandler interfaces the using the https://github.com/testcontainers/testcontainers-go package.
Package testcontainers provides implementations of the privatebtc.NodeService and privatebtc.NodeHandler interfaces the using the https://github.com/testcontainers/testcontainers-go package.
Package mock provides a mock implementation of the privatebtc package for testing purposes.
Package mock provides a mock implementation of the privatebtc package for testing purposes.
Package tview provides a Terminal User Interface for the Bitcoin Private Network implemented in the privatebtc package using https://github.com/rivo/tview
Package tview provides a Terminal User Interface for the Bitcoin Private Network implemented in the privatebtc package using https://github.com/rivo/tview

Jump to

Keyboard shortcuts

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