Merge pull request #1484 from wpaulino/bitcoind-0.19-compat
btcjson+rpcclient: add compatibility for bitcoind v0.19.0
This commit is contained in:
commit
4eac390191
10 changed files with 432 additions and 51 deletions
|
@ -638,6 +638,7 @@ func NewSearchRawTransactionsCmd(address string, verbose, skip, count *int, vinE
|
||||||
type SendRawTransactionCmd struct {
|
type SendRawTransactionCmd struct {
|
||||||
HexTx string
|
HexTx string
|
||||||
AllowHighFees *bool `jsonrpcdefault:"false"`
|
AllowHighFees *bool `jsonrpcdefault:"false"`
|
||||||
|
MaxFeeRate *int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
|
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
|
||||||
|
@ -652,6 +653,17 @@ func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
|
||||||
|
// sendrawtransaction JSON-RPC command to a bitcoind node.
|
||||||
|
//
|
||||||
|
// A 0 maxFeeRate indicates that a maximum fee rate won't be enforced.
|
||||||
|
func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTransactionCmd {
|
||||||
|
return &SendRawTransactionCmd{
|
||||||
|
HexTx: hexTx,
|
||||||
|
MaxFeeRate: &maxFeeRate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetGenerateCmd defines the setgenerate JSON-RPC command.
|
// SetGenerateCmd defines the setgenerate JSON-RPC command.
|
||||||
type SetGenerateCmd struct {
|
type SetGenerateCmd struct {
|
||||||
Generate bool
|
Generate bool
|
||||||
|
|
|
@ -92,11 +92,44 @@ type SoftForkDescription struct {
|
||||||
type Bip9SoftForkDescription struct {
|
type Bip9SoftForkDescription struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Bit uint8 `json:"bit"`
|
Bit uint8 `json:"bit"`
|
||||||
StartTime int64 `json:"startTime"`
|
StartTime1 int64 `json:"startTime"`
|
||||||
|
StartTime2 int64 `json:"start_time"`
|
||||||
Timeout int64 `json:"timeout"`
|
Timeout int64 `json:"timeout"`
|
||||||
Since int32 `json:"since"`
|
Since int32 `json:"since"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StartTime returns the starting time of the softfork as a Unix epoch.
|
||||||
|
func (d *Bip9SoftForkDescription) StartTime() int64 {
|
||||||
|
if d.StartTime1 != 0 {
|
||||||
|
return d.StartTime1
|
||||||
|
}
|
||||||
|
return d.StartTime2
|
||||||
|
}
|
||||||
|
|
||||||
|
// SoftForks describes the current softforks enabled by the backend. Softforks
|
||||||
|
// activated through BIP9 are grouped together separate from any other softforks
|
||||||
|
// with different activation types.
|
||||||
|
type SoftForks struct {
|
||||||
|
SoftForks []*SoftForkDescription `json:"softforks"`
|
||||||
|
Bip9SoftForks map[string]*Bip9SoftForkDescription `json:"bip9_softforks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnifiedSoftForks describes a softforks in a general manner, irrespective of
|
||||||
|
// its activation type. This was a format introduced by bitcoind v0.19.0
|
||||||
|
type UnifiedSoftFork struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
BIP9SoftForkDescription *Bip9SoftForkDescription `json:"bip9"`
|
||||||
|
Height int32 `json:"height"`
|
||||||
|
Active bool `json:"active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnifiedSoftForks describes the current softforks enabled the by the backend
|
||||||
|
// in a unified manner, i.e, softforks with different activation types are
|
||||||
|
// grouped together. This was a format introduced by bitcoind v0.19.0
|
||||||
|
type UnifiedSoftForks struct {
|
||||||
|
SoftForks map[string]*UnifiedSoftFork `json:"softforks"`
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlockChainInfoResult models the data returned from the getblockchaininfo
|
// GetBlockChainInfoResult models the data returned from the getblockchaininfo
|
||||||
// command.
|
// command.
|
||||||
type GetBlockChainInfoResult struct {
|
type GetBlockChainInfoResult struct {
|
||||||
|
@ -110,8 +143,8 @@ type GetBlockChainInfoResult struct {
|
||||||
Pruned bool `json:"pruned"`
|
Pruned bool `json:"pruned"`
|
||||||
PruneHeight int32 `json:"pruneheight,omitempty"`
|
PruneHeight int32 `json:"pruneheight,omitempty"`
|
||||||
ChainWork string `json:"chainwork,omitempty"`
|
ChainWork string `json:"chainwork,omitempty"`
|
||||||
SoftForks []*SoftForkDescription `json:"softforks"`
|
*SoftForks
|
||||||
Bip9SoftForks map[string]*Bip9SoftForkDescription `json:"bip9_softforks"`
|
*UnifiedSoftForks
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockTemplateResultTx models the transactions field of the
|
// GetBlockTemplateResultTx models the transactions field of the
|
||||||
|
|
|
@ -102,7 +102,7 @@ func assertSoftForkStatus(r *rpctest.Harness, t *testing.T, forkKey string, stat
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the key is available.
|
// Ensure the key is available.
|
||||||
desc, ok := info.Bip9SoftForks[forkKey]
|
desc, ok := info.SoftForks.Bip9SoftForks[forkKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
_, _, line, _ := runtime.Caller(1)
|
_, _, line, _ := runtime.Caller(1)
|
||||||
t.Fatalf("assertion failed at line %d: softfork status for %q "+
|
t.Fatalf("assertion failed at line %d: softfork status for %q "+
|
||||||
|
|
|
@ -253,16 +253,15 @@ func (c *Client) GetDifficulty() (float64, error) {
|
||||||
|
|
||||||
// FutureGetBlockChainInfoResult is a promise to deliver the result of a
|
// FutureGetBlockChainInfoResult is a promise to deliver the result of a
|
||||||
// GetBlockChainInfoAsync RPC invocation (or an applicable error).
|
// GetBlockChainInfoAsync RPC invocation (or an applicable error).
|
||||||
type FutureGetBlockChainInfoResult chan *response
|
type FutureGetBlockChainInfoResult struct {
|
||||||
|
client *Client
|
||||||
// Receive waits for the response promised by the future and returns chain info
|
Response chan *response
|
||||||
// result provided by the server.
|
}
|
||||||
func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResult, error) {
|
|
||||||
res, err := receiveFuture(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// unmarshalPartialGetBlockChainInfoResult unmarshals the response into an
|
||||||
|
// instance of GetBlockChainInfoResult without populating the SoftForks and
|
||||||
|
// UnifiedSoftForks fields.
|
||||||
|
func unmarshalPartialGetBlockChainInfoResult(res []byte) (*btcjson.GetBlockChainInfoResult, error) {
|
||||||
var chainInfo btcjson.GetBlockChainInfoResult
|
var chainInfo btcjson.GetBlockChainInfoResult
|
||||||
if err := json.Unmarshal(res, &chainInfo); err != nil {
|
if err := json.Unmarshal(res, &chainInfo); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -270,6 +269,59 @@ func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResu
|
||||||
return &chainInfo, nil
|
return &chainInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unmarshalGetBlockChainInfoResultSoftForks properly unmarshals the softforks
|
||||||
|
// related fields into the GetBlockChainInfoResult instance.
|
||||||
|
func unmarshalGetBlockChainInfoResultSoftForks(chainInfo *btcjson.GetBlockChainInfoResult,
|
||||||
|
version BackendVersion, res []byte) error {
|
||||||
|
|
||||||
|
switch version {
|
||||||
|
// Versions of bitcoind on or after v0.19.0 use the unified format.
|
||||||
|
case BitcoindPost19:
|
||||||
|
var softForks btcjson.UnifiedSoftForks
|
||||||
|
if err := json.Unmarshal(res, &softForks); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
chainInfo.UnifiedSoftForks = &softForks
|
||||||
|
|
||||||
|
// All other versions use the original format.
|
||||||
|
default:
|
||||||
|
var softForks btcjson.SoftForks
|
||||||
|
if err := json.Unmarshal(res, &softForks); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
chainInfo.SoftForks = &softForks
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive waits for the response promised by the future and returns chain info
|
||||||
|
// result provided by the server.
|
||||||
|
func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResult, error) {
|
||||||
|
res, err := receiveFuture(r.Response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
chainInfo, err := unmarshalPartialGetBlockChainInfoResult(res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspect the version to determine how we'll need to parse the
|
||||||
|
// softforks from the response.
|
||||||
|
version, err := r.client.BackendVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = unmarshalGetBlockChainInfoResultSoftForks(chainInfo, version, res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return chainInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlockChainInfoAsync returns an instance of a type that can be used to get
|
// GetBlockChainInfoAsync returns an instance of a type that can be used to get
|
||||||
// the result of the RPC at some future time by invoking the Receive function
|
// the result of the RPC at some future time by invoking the Receive function
|
||||||
// on the returned instance.
|
// on the returned instance.
|
||||||
|
@ -277,7 +329,10 @@ func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResu
|
||||||
// See GetBlockChainInfo for the blocking version and more details.
|
// See GetBlockChainInfo for the blocking version and more details.
|
||||||
func (c *Client) GetBlockChainInfoAsync() FutureGetBlockChainInfoResult {
|
func (c *Client) GetBlockChainInfoAsync() FutureGetBlockChainInfoResult {
|
||||||
cmd := btcjson.NewGetBlockChainInfoCmd()
|
cmd := btcjson.NewGetBlockChainInfoCmd()
|
||||||
return c.sendCmd(cmd)
|
return FutureGetBlockChainInfoResult{
|
||||||
|
client: c,
|
||||||
|
Response: c.sendCmd(cmd),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockChainInfo returns information related to the processing state of
|
// GetBlockChainInfo returns information related to the processing state of
|
||||||
|
|
92
rpcclient/chain_test.go
Normal file
92
rpcclient/chain_test.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package rpcclient
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// TestUnmarshalGetBlockChainInfoResult ensures that the SoftForks and
|
||||||
|
// UnifiedSoftForks fields of GetBlockChainInfoResult are properly unmarshaled
|
||||||
|
// when using the expected backend version.
|
||||||
|
func TestUnmarshalGetBlockChainInfoResultSoftForks(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
version BackendVersion
|
||||||
|
res []byte
|
||||||
|
compatible bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "bitcoind < 0.19.0 with separate softforks",
|
||||||
|
version: BitcoindPre19,
|
||||||
|
res: []byte(`{"softforks": [{"version": 2}]}`),
|
||||||
|
compatible: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bitcoind >= 0.19.0 with separate softforks",
|
||||||
|
version: BitcoindPost19,
|
||||||
|
res: []byte(`{"softforks": [{"version": 2}]}`),
|
||||||
|
compatible: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bitcoind < 0.19.0 with unified softforks",
|
||||||
|
version: BitcoindPre19,
|
||||||
|
res: []byte(`{"softforks": {"segwit": {"type": "bip9"}}}`),
|
||||||
|
compatible: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bitcoind >= 0.19.0 with unified softforks",
|
||||||
|
version: BitcoindPost19,
|
||||||
|
res: []byte(`{"softforks": {"segwit": {"type": "bip9"}}}`),
|
||||||
|
compatible: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
success := t.Run(test.name, func(t *testing.T) {
|
||||||
|
// We'll start by unmarshaling the JSON into a struct.
|
||||||
|
// The SoftForks and UnifiedSoftForks field should not
|
||||||
|
// be set yet, as they are unmarshaled within a
|
||||||
|
// different function.
|
||||||
|
info, err := unmarshalPartialGetBlockChainInfoResult(test.res)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if info.SoftForks != nil {
|
||||||
|
t.Fatal("expected SoftForks to be empty")
|
||||||
|
}
|
||||||
|
if info.UnifiedSoftForks != nil {
|
||||||
|
t.Fatal("expected UnifiedSoftForks to be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proceed to unmarshal the softforks of the response
|
||||||
|
// with the expected version. If the version is
|
||||||
|
// incompatible with the response, then this should
|
||||||
|
// fail.
|
||||||
|
err = unmarshalGetBlockChainInfoResultSoftForks(
|
||||||
|
info, test.version, test.res,
|
||||||
|
)
|
||||||
|
if test.compatible && err != nil {
|
||||||
|
t.Fatalf("unable to unmarshal softforks: %v", err)
|
||||||
|
}
|
||||||
|
if !test.compatible && err == nil {
|
||||||
|
t.Fatal("expected to not unmarshal softforks")
|
||||||
|
}
|
||||||
|
if !test.compatible {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the version is compatible with the response, we
|
||||||
|
// should expect to see the proper softforks field set.
|
||||||
|
if test.version == BitcoindPost19 &&
|
||||||
|
info.SoftForks != nil {
|
||||||
|
t.Fatal("expected SoftForks to be empty")
|
||||||
|
}
|
||||||
|
if test.version == BitcoindPre19 &&
|
||||||
|
info.UnifiedSoftForks != nil {
|
||||||
|
t.Fatal("expected UnifiedSoftForks to be empty")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if !success {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -103,6 +104,22 @@ type jsonRequest struct {
|
||||||
responseChan chan *response
|
responseChan chan *response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BackendVersion represents the version of the backend the client is currently
|
||||||
|
// connected to.
|
||||||
|
type BackendVersion uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// BitcoindPre19 represents a bitcoind version before 0.19.0.
|
||||||
|
BitcoindPre19 BackendVersion = iota
|
||||||
|
|
||||||
|
// BitcoindPost19 represents a bitcoind version equal to or greater than
|
||||||
|
// 0.19.0.
|
||||||
|
BitcoindPost19
|
||||||
|
|
||||||
|
// Btcd represents a catch-all btcd version.
|
||||||
|
Btcd
|
||||||
|
)
|
||||||
|
|
||||||
// Client represents a Bitcoin RPC client which allows easy access to the
|
// Client represents a Bitcoin RPC client which allows easy access to the
|
||||||
// various RPC methods available on a Bitcoin RPC server. Each of the wrapper
|
// various RPC methods available on a Bitcoin RPC server. Each of the wrapper
|
||||||
// functions handle the details of converting the passed and return types to and
|
// functions handle the details of converting the passed and return types to and
|
||||||
|
@ -129,6 +146,11 @@ type Client struct {
|
||||||
// POST mode.
|
// POST mode.
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
|
|
||||||
|
// backendVersion is the version of the backend the client is currently
|
||||||
|
// connected to. This should be retrieved through GetVersion.
|
||||||
|
backendVersionMu sync.Mutex
|
||||||
|
backendVersion *BackendVersion
|
||||||
|
|
||||||
// mtx is a mutex to protect access to connection related fields.
|
// mtx is a mutex to protect access to connection related fields.
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
|
|
||||||
|
@ -659,6 +681,12 @@ out:
|
||||||
log.Infof("Reestablished connection to RPC server %s",
|
log.Infof("Reestablished connection to RPC server %s",
|
||||||
c.config.Host)
|
c.config.Host)
|
||||||
|
|
||||||
|
// Reset the version in case the backend was
|
||||||
|
// disconnected due to an upgrade.
|
||||||
|
c.backendVersionMu.Lock()
|
||||||
|
c.backendVersion = nil
|
||||||
|
c.backendVersionMu.Unlock()
|
||||||
|
|
||||||
// Reset the connection state and signal the reconnect
|
// Reset the connection state and signal the reconnect
|
||||||
// has happened.
|
// has happened.
|
||||||
c.wsConn = wsConn
|
c.wsConn = wsConn
|
||||||
|
@ -1332,3 +1360,84 @@ func (c *Client) Connect(tries int) error {
|
||||||
// All connection attempts failed, so return the last error.
|
// All connection attempts failed, so return the last error.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// bitcoind19Str is the string representation of bitcoind v0.19.0.
|
||||||
|
bitcoind19Str = "0.19.0"
|
||||||
|
|
||||||
|
// bitcoindVersionPrefix specifies the prefix included in every bitcoind
|
||||||
|
// version exposed through GetNetworkInfo.
|
||||||
|
bitcoindVersionPrefix = "/Satoshi:"
|
||||||
|
|
||||||
|
// bitcoindVersionSuffix specifies the suffix included in every bitcoind
|
||||||
|
// version exposed through GetNetworkInfo.
|
||||||
|
bitcoindVersionSuffix = "/"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseBitcoindVersion parses the bitcoind version from its string
|
||||||
|
// representation.
|
||||||
|
func parseBitcoindVersion(version string) BackendVersion {
|
||||||
|
// Trim the version of its prefix and suffix to determine the
|
||||||
|
// appropriate version number.
|
||||||
|
version = strings.TrimPrefix(
|
||||||
|
strings.TrimSuffix(version, bitcoindVersionSuffix),
|
||||||
|
bitcoindVersionPrefix,
|
||||||
|
)
|
||||||
|
switch {
|
||||||
|
case version < bitcoind19Str:
|
||||||
|
return BitcoindPre19
|
||||||
|
default:
|
||||||
|
return BitcoindPost19
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackendVersion retrieves the version of the backend the client is currently
|
||||||
|
// connected to.
|
||||||
|
func (c *Client) BackendVersion() (BackendVersion, error) {
|
||||||
|
c.backendVersionMu.Lock()
|
||||||
|
defer c.backendVersionMu.Unlock()
|
||||||
|
|
||||||
|
if c.backendVersion != nil {
|
||||||
|
return *c.backendVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll start by calling GetInfo. This method doesn't exist for
|
||||||
|
// bitcoind nodes as of v0.16.0, so we'll assume the client is connected
|
||||||
|
// to a btcd backend if it does exist.
|
||||||
|
info, err := c.GetInfo()
|
||||||
|
|
||||||
|
switch err := err.(type) {
|
||||||
|
// Parse the btcd version and cache it.
|
||||||
|
case nil:
|
||||||
|
log.Debugf("Detected btcd version: %v", info.Version)
|
||||||
|
version := Btcd
|
||||||
|
c.backendVersion = &version
|
||||||
|
return *c.backendVersion, nil
|
||||||
|
|
||||||
|
// Inspect the RPC error to ensure the method was not found, otherwise
|
||||||
|
// we actually ran into an error.
|
||||||
|
case *btcjson.RPCError:
|
||||||
|
if err.Code != btcjson.ErrRPCMethodNotFound.Code {
|
||||||
|
return 0, fmt.Errorf("unable to detect btcd version: "+
|
||||||
|
"%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("unable to detect btcd version: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the GetInfo method was not found, we assume the client is
|
||||||
|
// connected to a bitcoind backend, which exposes its version through
|
||||||
|
// GetNetworkInfo.
|
||||||
|
networkInfo, err := c.GetNetworkInfo()
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("unable to detect bitcoind version: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the bitcoind version and cache it.
|
||||||
|
log.Debugf("Detected bitcoind version: %v", networkInfo.SubVersion)
|
||||||
|
version := parseBitcoindVersion(networkInfo.SubVersion)
|
||||||
|
c.backendVersion = &version
|
||||||
|
|
||||||
|
return *c.backendVersion, nil
|
||||||
|
}
|
||||||
|
|
|
@ -244,6 +244,43 @@ func (c *Client) Ping() error {
|
||||||
return c.PingAsync().Receive()
|
return c.PingAsync().Receive()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FutureGetNetworkInfoResult is a future promise to deliver the result of a
|
||||||
|
// GetNetworkInfoAsync RPC invocation (or an applicable error).
|
||||||
|
type FutureGetNetworkInfoResult chan *response
|
||||||
|
|
||||||
|
// Receive waits for the response promised by the future and returns data about
|
||||||
|
// the current network.
|
||||||
|
func (r FutureGetNetworkInfoResult) Receive() (*btcjson.GetNetworkInfoResult, error) {
|
||||||
|
res, err := receiveFuture(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal result as an array of getpeerinfo result objects.
|
||||||
|
var networkInfo btcjson.GetNetworkInfoResult
|
||||||
|
err = json.Unmarshal(res, &networkInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &networkInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkInfoAsync returns an instance of a type that can be used to get the
|
||||||
|
// result of the RPC at some future time by invoking the Receive function on the
|
||||||
|
// returned instance.
|
||||||
|
//
|
||||||
|
// See GetNetworkInfo for the blocking version and more details.
|
||||||
|
func (c *Client) GetNetworkInfoAsync() FutureGetNetworkInfoResult {
|
||||||
|
cmd := btcjson.NewGetNetworkInfoCmd()
|
||||||
|
return c.sendCmd(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkInfo returns data about the current network.
|
||||||
|
func (c *Client) GetNetworkInfo() (*btcjson.GetNetworkInfoResult, error) {
|
||||||
|
return c.GetNetworkInfoAsync().Receive()
|
||||||
|
}
|
||||||
|
|
||||||
// FutureGetPeerInfoResult is a future promise to deliver the result of a
|
// FutureGetPeerInfoResult is a future promise to deliver the result of a
|
||||||
// GetPeerInfoAsync RPC invocation (or an applicable error).
|
// GetPeerInfoAsync RPC invocation (or an applicable error).
|
||||||
type FutureGetPeerInfoResult chan *response
|
type FutureGetPeerInfoResult chan *response
|
||||||
|
|
|
@ -15,6 +15,12 @@ import (
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// defaultMaxFeeRate is the default maximum fee rate in sat/KB enforced
|
||||||
|
// by bitcoind v0.19.0 or after for transaction broadcast.
|
||||||
|
defaultMaxFeeRate = btcutil.SatoshiPerBitcoin / 10
|
||||||
|
)
|
||||||
|
|
||||||
// SigHashType enumerates the available signature hashing types that the
|
// SigHashType enumerates the available signature hashing types that the
|
||||||
// SignRawTransaction function accepts.
|
// SignRawTransaction function accepts.
|
||||||
type SigHashType string
|
type SigHashType string
|
||||||
|
@ -296,7 +302,31 @@ func (c *Client) SendRawTransactionAsync(tx *wire.MsgTx, allowHighFees bool) Fut
|
||||||
txHex = hex.EncodeToString(buf.Bytes())
|
txHex = hex.EncodeToString(buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := btcjson.NewSendRawTransactionCmd(txHex, &allowHighFees)
|
// Due to differences in the sendrawtransaction API for different
|
||||||
|
// backends, we'll need to inspect our version and construct the
|
||||||
|
// appropriate request.
|
||||||
|
version, err := c.BackendVersion()
|
||||||
|
if err != nil {
|
||||||
|
return newFutureError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmd *btcjson.SendRawTransactionCmd
|
||||||
|
switch version {
|
||||||
|
// Starting from bitcoind v0.19.0, the MaxFeeRate field should be used.
|
||||||
|
case BitcoindPost19:
|
||||||
|
// Using a 0 MaxFeeRate is interpreted as a maximum fee rate not
|
||||||
|
// being enforced by bitcoind.
|
||||||
|
var maxFeeRate int32
|
||||||
|
if !allowHighFees {
|
||||||
|
maxFeeRate = defaultMaxFeeRate
|
||||||
|
}
|
||||||
|
cmd = btcjson.NewBitcoindSendRawTransactionCmd(txHex, maxFeeRate)
|
||||||
|
|
||||||
|
// Otherwise, use the AllowHighFees field.
|
||||||
|
default:
|
||||||
|
cmd = btcjson.NewSendRawTransactionCmd(txHex, &allowHighFees)
|
||||||
|
}
|
||||||
|
|
||||||
return c.sendCmd(cmd)
|
return c.sendCmd(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1198,14 +1198,16 @@ func handleGetBlockChainInfo(s *rpcServer, cmd interface{}, closeChan <-chan str
|
||||||
Difficulty: getDifficultyRatio(chainSnapshot.Bits, params),
|
Difficulty: getDifficultyRatio(chainSnapshot.Bits, params),
|
||||||
MedianTime: chainSnapshot.MedianTime.Unix(),
|
MedianTime: chainSnapshot.MedianTime.Unix(),
|
||||||
Pruned: false,
|
Pruned: false,
|
||||||
|
SoftForks: &btcjson.SoftForks{
|
||||||
Bip9SoftForks: make(map[string]*btcjson.Bip9SoftForkDescription),
|
Bip9SoftForks: make(map[string]*btcjson.Bip9SoftForkDescription),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, populate the response with information describing the current
|
// Next, populate the response with information describing the current
|
||||||
// status of soft-forks deployed via the super-majority block
|
// status of soft-forks deployed via the super-majority block
|
||||||
// signalling mechanism.
|
// signalling mechanism.
|
||||||
height := chainSnapshot.Height
|
height := chainSnapshot.Height
|
||||||
chainInfo.SoftForks = []*btcjson.SoftForkDescription{
|
chainInfo.SoftForks.SoftForks = []*btcjson.SoftForkDescription{
|
||||||
{
|
{
|
||||||
ID: "bip34",
|
ID: "bip34",
|
||||||
Version: 2,
|
Version: 2,
|
||||||
|
@ -1281,10 +1283,10 @@ func handleGetBlockChainInfo(s *rpcServer, cmd interface{}, closeChan <-chan str
|
||||||
|
|
||||||
// Finally, populate the soft-fork description with all the
|
// Finally, populate the soft-fork description with all the
|
||||||
// information gathered above.
|
// information gathered above.
|
||||||
chainInfo.Bip9SoftForks[forkName] = &btcjson.Bip9SoftForkDescription{
|
chainInfo.SoftForks.Bip9SoftForks[forkName] = &btcjson.Bip9SoftForkDescription{
|
||||||
Status: strings.ToLower(statusString),
|
Status: strings.ToLower(statusString),
|
||||||
Bit: deploymentDetails.BitNumber,
|
Bit: deploymentDetails.BitNumber,
|
||||||
StartTime: int64(deploymentDetails.StartTime),
|
StartTime2: int64(deploymentDetails.StartTime),
|
||||||
Timeout: int64(deploymentDetails.ExpireTime),
|
Timeout: int64(deploymentDetails.ExpireTime),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,10 +183,7 @@ var helpDescsEnUS = map[string]string{
|
||||||
"getblockchaininforesult-pruneheight": "The lowest block retained in the current pruned chain",
|
"getblockchaininforesult-pruneheight": "The lowest block retained in the current pruned chain",
|
||||||
"getblockchaininforesult-chainwork": "The total cumulative work in the best chain",
|
"getblockchaininforesult-chainwork": "The total cumulative work in the best chain",
|
||||||
"getblockchaininforesult-softforks": "The status of the super-majority soft-forks",
|
"getblockchaininforesult-softforks": "The status of the super-majority soft-forks",
|
||||||
"getblockchaininforesult-bip9_softforks": "JSON object describing active BIP0009 deployments",
|
"getblockchaininforesult-unifiedsoftforks": "The status of the super-majority soft-forks used by bitcoind on or after v0.19.0",
|
||||||
"getblockchaininforesult-bip9_softforks--key": "bip9_softforks",
|
|
||||||
"getblockchaininforesult-bip9_softforks--value": "An object describing a particular BIP009 deployment",
|
|
||||||
"getblockchaininforesult-bip9_softforks--desc": "The status of any defined BIP0009 soft-fork deployments",
|
|
||||||
|
|
||||||
// SoftForkDescription help.
|
// SoftForkDescription help.
|
||||||
"softforkdescription-reject": "The current activation status of the softfork",
|
"softforkdescription-reject": "The current activation status of the softfork",
|
||||||
|
@ -194,6 +191,19 @@ var helpDescsEnUS = map[string]string{
|
||||||
"softforkdescription-id": "The string identifier for the soft fork",
|
"softforkdescription-id": "The string identifier for the soft fork",
|
||||||
"-status": "A bool which indicates if the soft fork is active",
|
"-status": "A bool which indicates if the soft fork is active",
|
||||||
|
|
||||||
|
// SoftForks help.
|
||||||
|
"softforks-softforks": "The status of the super-majority soft-forks",
|
||||||
|
"softforks-bip9_softforks": "JSON object describing active BIP0009 deployments",
|
||||||
|
"softforks-bip9_softforks--key": "bip9_softforks",
|
||||||
|
"softforks-bip9_softforks--value": "An object describing a particular BIP009 deployment",
|
||||||
|
"softforks-bip9_softforks--desc": "The status of any defined BIP0009 soft-fork deployments",
|
||||||
|
|
||||||
|
// UnifiedSoftForks help.
|
||||||
|
"unifiedsoftforks-softforks": "The status of the super-majority soft-forks used by bitcoind on or after v0.19.0",
|
||||||
|
"unifiedsoftforks-softforks--key": "softforks",
|
||||||
|
"unifiedsoftforks-softforks--value": "An object describing an active softfork deployment used by bitcoind on or after v0.19.0",
|
||||||
|
"unifiedsoftforks-softforks--desc": "JSON object describing an active softfork deployment used by bitcoind on or after v0.19.0",
|
||||||
|
|
||||||
// TxRawResult help.
|
// TxRawResult help.
|
||||||
"txrawresult-hex": "Hex-encoded transaction",
|
"txrawresult-hex": "Hex-encoded transaction",
|
||||||
"txrawresult-txid": "The hash of the transaction",
|
"txrawresult-txid": "The hash of the transaction",
|
||||||
|
@ -542,6 +552,7 @@ var helpDescsEnUS = map[string]string{
|
||||||
"sendrawtransaction--synopsis": "Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.",
|
"sendrawtransaction--synopsis": "Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.",
|
||||||
"sendrawtransaction-hextx": "Serialized, hex-encoded signed transaction",
|
"sendrawtransaction-hextx": "Serialized, hex-encoded signed transaction",
|
||||||
"sendrawtransaction-allowhighfees": "Whether or not to allow insanely high fees (btcd does not yet implement this parameter, so it has no effect)",
|
"sendrawtransaction-allowhighfees": "Whether or not to allow insanely high fees (btcd does not yet implement this parameter, so it has no effect)",
|
||||||
|
"sendrawtransaction-maxfeerate": "Used by bitcoind on or after v0.19.0",
|
||||||
"sendrawtransaction--result0": "The hash of the transaction",
|
"sendrawtransaction--result0": "The hash of the transaction",
|
||||||
|
|
||||||
// SetGenerateCmd help.
|
// SetGenerateCmd help.
|
||||||
|
|
Loading…
Reference in a new issue