fix vendor folder

This commit is contained in:
Juan Pablo Civile
2019-12-16 17:59:11 -03:00
parent 240b7f00bd
commit a60e97ace6
72 changed files with 1551 additions and 6487 deletions

View File

@@ -36,10 +36,17 @@ var (
// interface from crypto/elliptic.
type KoblitzCurve struct {
*elliptic.CurveParams
q *big.Int
// q is the value (P+1)/4 used to compute the square root of field
// elements.
q *big.Int
H int // cofactor of the curve.
halfOrder *big.Int // half the order N
// fieldB is the constant B of the curve as a fieldVal.
fieldB *fieldVal
// byteSize is simply the bit size / 8 and is provided for convenience
// since it is calculated repeatedly.
byteSize int
@@ -879,12 +886,22 @@ func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
return curve.fieldJacobianToBigAffine(qx, qy, qz)
}
// QPlus1Div4 returns the Q+1/4 constant for the curve for use in calculating
// square roots via exponention.
// QPlus1Div4 returns the (P+1)/4 constant for the curve for use in calculating
// square roots via exponentiation.
//
// DEPRECATED: The actual value returned is (P+1)/4, where as the original
// method name implies that this value is (((P+1)/4)+1)/4. This method is kept
// to maintain backwards compatibility of the API. Use Q() instead.
func (curve *KoblitzCurve) QPlus1Div4() *big.Int {
return curve.q
}
// Q returns the (P+1)/4 constant for the curve for use in calculating square
// roots via exponentiation.
func (curve *KoblitzCurve) Q() *big.Int {
return curve.q
}
var initonce sync.Once
var secp256k1 KoblitzCurve
@@ -917,6 +934,7 @@ func initS256() {
big.NewInt(1)), big.NewInt(4))
secp256k1.H = 1
secp256k1.halfOrder = new(big.Int).Rsh(secp256k1.N, 1)
secp256k1.fieldB = new(fieldVal).SetByteSlice(secp256k1.B.Bytes())
// Provided for convenience since this gets computed repeatedly.
secp256k1.byteSize = secp256k1.BitSize / 8

View File

@@ -102,6 +102,20 @@ const (
fieldPrimeWordOne = 0x3ffffbf
)
var (
// fieldQBytes is the value Q = (P+1)/4 for the secp256k1 prime P. This
// value is used to efficiently compute the square root of values in the
// field via exponentiation. The value of Q in hex is:
//
// Q = 3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c
fieldQBytes = []byte{
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x0c,
}
)
// fieldVal implements optimized fixed-precision arithmetic over the
// secp256k1 finite field. This means all arithmetic is performed modulo
// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. It
@@ -1221,3 +1235,118 @@ func (f *fieldVal) Inverse() *fieldVal {
f.Square().Square().Square().Square().Square() // f = a^(2^256 - 4294968320)
return f.Mul(&a45) // f = a^(2^256 - 4294968275) = a^(p-2)
}
// SqrtVal computes the square root of x modulo the curve's prime, and stores
// the result in f. The square root is computed via exponentiation of x by the
// value Q = (P+1)/4 using the curve's precomputed big-endian representation of
// the Q. This method uses a modified version of square-and-multiply
// exponentiation over secp256k1 fieldVals to operate on bytes instead of bits,
// which offers better performance over both big.Int exponentiation and bit-wise
// square-and-multiply.
//
// NOTE: This method only works when P is intended to be the secp256k1 prime and
// is not constant time. The returned value is of magnitude 1, but is
// denormalized.
func (f *fieldVal) SqrtVal(x *fieldVal) *fieldVal {
// The following computation iteratively computes x^((P+1)/4) = x^Q
// using the recursive, piece-wise definition:
//
// x^n = (x^2)^(n/2) mod P if n is even
// x^n = x(x^2)^(n-1/2) mod P if n is odd
//
// Given n in its big-endian representation b_k, ..., b_0, x^n can be
// computed by defining the sequence r_k+1, ..., r_0, where:
//
// r_k+1 = 1
// r_i = (r_i+1)^2 * x^b_i for i = k, ..., 0
//
// The final value r_0 = x^n.
//
// See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more
// details.
//
// This can be further optimized, by observing that the value of Q in
// secp256k1 has the value:
//
// Q = 3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c
//
// We can unroll the typical bit-wise interpretation of the
// exponentiation algorithm above to instead operate on bytes.
// This reduces the number of comparisons by an order of magnitude,
// reducing the overhead of failed branch predictions and additional
// comparisons in this method.
//
// Since there there are only 4 unique bytes of Q, this keeps the jump
// table small without the need to handle all possible 8-bit values.
// Further, we observe that 29 of the 32 bytes are 0xff; making the
// first case handle 0xff therefore optimizes the hot path.
f.SetInt(1)
for _, b := range fieldQBytes {
switch b {
// Most common case, where all 8 bits are set.
case 0xff:
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
// First byte of Q (0x3f), where all but the top two bits are
// set. Note that this case only applies six operations, since
// the highest bit of Q resides in bit six of the first byte. We
// ignore the first two bits, since squaring for these bits will
// result in an invalid result. We forgo squaring f before the
// first multiply, since 1^2 = 1.
case 0x3f:
f.Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
// Byte 28 of Q (0xbf), where only bit 7 is unset.
case 0xbf:
f.Square().Mul(x)
f.Square()
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
// Byte 31 of Q (0x0c), where only bits 3 and 4 are set.
default:
f.Square()
f.Square()
f.Square()
f.Square()
f.Square().Mul(x)
f.Square().Mul(x)
f.Square()
f.Square()
}
}
return f
}
// Sqrt computes the square root of f modulo the curve's prime, and stores the
// result in f. The square root is computed via exponentiation of x by the value
// Q = (P+1)/4 using the curve's precomputed big-endian representation of the Q.
// This method uses a modified version of square-and-multiply exponentiation
// over secp256k1 fieldVals to operate on bytes instead of bits, which offers
// better performance over both big.Int exponentiation and bit-wise
// square-and-multiply.
//
// NOTE: This method only works when P is intended to be the secp256k1 prime and
// is not constant time. The returned value is of magnitude 1, but is
// denormalized.
func (f *fieldVal) Sqrt() *fieldVal {
return f.SqrtVal(f)
}

View File

@@ -1,63 +0,0 @@
// Copyright 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
// This file is ignored during the regular build due to the following build tag.
// It is called by go generate and used to automatically generate pre-computed
// tables used to accelerate operations.
// +build ignore
package main
import (
"bytes"
"compress/zlib"
"encoding/base64"
"fmt"
"log"
"os"
"github.com/btcsuite/btcd/btcec"
)
func main() {
fi, err := os.Create("secp256k1.go")
if err != nil {
log.Fatal(err)
}
defer fi.Close()
// Compress the serialized byte points.
serialized := btcec.S256().SerializedBytePoints()
var compressed bytes.Buffer
w := zlib.NewWriter(&compressed)
if _, err := w.Write(serialized); err != nil {
fmt.Println(err)
os.Exit(1)
}
w.Close()
// Encode the compressed byte points with base64.
encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len()))
base64.StdEncoding.Encode(encoded, compressed.Bytes())
fmt.Fprintln(fi, "// Copyright (c) 2015 The btcsuite developers")
fmt.Fprintln(fi, "// Use of this source code is governed by an ISC")
fmt.Fprintln(fi, "// license that can be found in the LICENSE file.")
fmt.Fprintln(fi)
fmt.Fprintln(fi, "package btcec")
fmt.Fprintln(fi)
fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)")
fmt.Fprintln(fi, "// DO NOT EDIT")
fmt.Fprintln(fi)
fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded))
a1, b1, a2, b2 := btcec.S256().EndomorphismVectors()
fmt.Println("The following values are the computed linearly " +
"independent vectors needed to make use of the secp256k1 " +
"endomorphism:")
fmt.Printf("a1: %x\n", a1)
fmt.Printf("b1: %x\n", b1)
fmt.Printf("a2: %x\n", a2)
fmt.Printf("b2: %x\n", b2)
}

View File

@@ -22,41 +22,40 @@ func isOdd(a *big.Int) bool {
return a.Bit(0) == 1
}
// decompressPoint decompresses a point on the given curve given the X point and
// decompressPoint decompresses a point on the secp256k1 curve given the X point and
// the solution to use.
func decompressPoint(curve *KoblitzCurve, x *big.Int, ybit bool) (*big.Int, error) {
// TODO: This will probably only work for secp256k1 due to
// optimizations.
func decompressPoint(curve *KoblitzCurve, bigX *big.Int, ybit bool) (*big.Int, error) {
var x fieldVal
x.SetByteSlice(bigX.Bytes())
// Y = +-sqrt(x^3 + B)
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
x3.Add(x3, curve.Params().B)
x3.Mod(x3, curve.Params().P)
// Compute x^3 + B mod p.
var x3 fieldVal
x3.SquareVal(&x).Mul(&x)
x3.Add(curve.fieldB).Normalize()
// Now calculate sqrt mod p of x^3 + B
// This code used to do a full sqrt based on tonelli/shanks,
// but this was replaced by the algorithms referenced in
// https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294
y := new(big.Int).Exp(x3, curve.QPlus1Div4(), curve.Params().P)
if ybit != isOdd(y) {
y.Sub(curve.Params().P, y)
var y fieldVal
y.SqrtVal(&x3).Normalize()
if ybit != y.IsOdd() {
y.Negate(1).Normalize()
}
// Check that y is a square root of x^3 + B.
y2 := new(big.Int).Mul(y, y)
y2.Mod(y2, curve.Params().P)
if y2.Cmp(x3) != 0 {
var y2 fieldVal
y2.SquareVal(&y).Normalize()
if !y2.Equals(&x3) {
return nil, fmt.Errorf("invalid square root")
}
// Verify that y-coord has expected parity.
if ybit != isOdd(y) {
if ybit != y.IsOdd() {
return nil, fmt.Errorf("ybit doesn't match oddness")
}
return y, nil
return new(big.Int).SetBytes(y.Bytes()[:]), nil
}
const (
@@ -102,6 +101,17 @@ func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *PublicKey, err err
if format == pubkeyHybrid && ybit != isOdd(pubkey.Y) {
return nil, fmt.Errorf("ybit doesn't match oddness")
}
if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, fmt.Errorf("pubkey X parameter is >= to P")
}
if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, fmt.Errorf("pubkey Y parameter is >= to P")
}
if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) {
return nil, fmt.Errorf("pubkey isn't on secp256k1 curve")
}
case PubKeyBytesLenCompressed:
// format is 0x2 | solution, <X coordinate>
// solution determines which solution of the curve we use.
@@ -115,20 +125,12 @@ func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *PublicKey, err err
if err != nil {
return nil, err
}
default: // wrong!
return nil, fmt.Errorf("invalid pub key length %d",
len(pubKeyStr))
}
if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, fmt.Errorf("pubkey X parameter is >= to P")
}
if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, fmt.Errorf("pubkey Y parameter is >= to P")
}
if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) {
return nil, fmt.Errorf("pubkey isn't on secp256k1 curve")
}
return &pubkey, nil
}

View File

@@ -276,7 +276,7 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
}
// recoverKeyFromSignature recovers a public key from the signature "sig" on the
// given message hash "msg". Based on the algorithm found in section 5.1.5 of
// given message hash "msg". Based on the algorithm found in section 4.1.6 of
// SEC 1 Ver 2.0, page 47-48 (53 and 54 in the pdf). This performs the details
// in the inner loop in Step 1. The counter provided is actually the j parameter
// of the loop * 2 - on the first iteration of j we do the R case, else the -R

View File

@@ -638,6 +638,7 @@ func NewSearchRawTransactionsCmd(address string, verbose, skip, count *int, vinE
type SendRawTransactionCmd struct {
HexTx string
AllowHighFees *bool `jsonrpcdefault:"false"`
MaxFeeRate *int32
}
// 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.
type SetGenerateCmd struct {
Generate bool

View File

@@ -90,28 +90,61 @@ type SoftForkDescription struct {
// Bip9SoftForkDescription describes the current state of a defined BIP0009
// version bits soft-fork.
type Bip9SoftForkDescription struct {
Status string `json:"status"`
Bit uint8 `json:"bit"`
StartTime int64 `json:"startTime"`
Timeout int64 `json:"timeout"`
Since int32 `json:"since"`
Status string `json:"status"`
Bit uint8 `json:"bit"`
StartTime1 int64 `json:"startTime"`
StartTime2 int64 `json:"start_time"`
Timeout int64 `json:"timeout"`
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
// command.
type GetBlockChainInfoResult struct {
Chain string `json:"chain"`
Blocks int32 `json:"blocks"`
Headers int32 `json:"headers"`
BestBlockHash string `json:"bestblockhash"`
Difficulty float64 `json:"difficulty"`
MedianTime int64 `json:"mediantime"`
VerificationProgress float64 `json:"verificationprogress,omitempty"`
Pruned bool `json:"pruned"`
PruneHeight int32 `json:"pruneheight,omitempty"`
ChainWork string `json:"chainwork,omitempty"`
SoftForks []*SoftForkDescription `json:"softforks"`
Bip9SoftForks map[string]*Bip9SoftForkDescription `json:"bip9_softforks"`
Chain string `json:"chain"`
Blocks int32 `json:"blocks"`
Headers int32 `json:"headers"`
BestBlockHash string `json:"bestblockhash"`
Difficulty float64 `json:"difficulty"`
MedianTime int64 `json:"mediantime"`
VerificationProgress float64 `json:"verificationprogress,omitempty"`
Pruned bool `json:"pruned"`
PruneHeight int32 `json:"pruneheight,omitempty"`
ChainWork string `json:"chainwork,omitempty"`
*SoftForks
*UnifiedSoftForks
}
// GetBlockTemplateResultTx models the transactions field of the
@@ -265,6 +298,7 @@ type GetPeerInfoResult struct {
type GetRawMempoolVerboseResult struct {
Size int32 `json:"size"`
Vsize int32 `json:"vsize"`
Weight int32 `json:"weight"`
Fee float64 `json:"fee"`
Time int64 `json:"time"`
Height int64 `json:"height"`
@@ -505,6 +539,7 @@ type TxRawResult struct {
Hash string `json:"hash,omitempty"`
Size int32 `json:"size,omitempty"`
Vsize int32 `json:"vsize,omitempty"`
Weight int32 `json:"weight,omitempty"`
Version int32 `json:"version"`
LockTime uint32 `json:"locktime"`
Vin []Vin `json:"vin"`
@@ -523,6 +558,7 @@ type SearchRawTransactionsResult struct {
Hash string `json:"hash"`
Size string `json:"size"`
Vsize string `json:"vsize"`
Weight string `json:"weight"`
Version int32 `json:"version"`
LockTime uint32 `json:"locktime"`
Vin []VinPrevOut `json:"vin"`

View File

@@ -253,16 +253,15 @@ func (c *Client) GetDifficulty() (float64, error) {
// FutureGetBlockChainInfoResult is a promise to deliver the result of a
// GetBlockChainInfoAsync RPC invocation (or an applicable error).
type FutureGetBlockChainInfoResult chan *response
// 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)
if err != nil {
return nil, err
}
type FutureGetBlockChainInfoResult struct {
client *Client
Response chan *response
}
// 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
if err := json.Unmarshal(res, &chainInfo); err != nil {
return nil, err
@@ -270,6 +269,59 @@ func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResu
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
// the result of the RPC at some future time by invoking the Receive function
// on the returned instance.
@@ -277,7 +329,10 @@ func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResu
// See GetBlockChainInfo for the blocking version and more details.
func (c *Client) GetBlockChainInfoAsync() FutureGetBlockChainInfoResult {
cmd := btcjson.NewGetBlockChainInfoCmd()
return c.sendCmd(cmd)
return FutureGetBlockChainInfoResult{
client: c,
Response: c.sendCmd(cmd),
}
}
// GetBlockChainInfo returns information related to the processing state of

View File

@@ -19,6 +19,7 @@ import (
"net"
"net/http"
"net/url"
"strings"
"sync"
"sync/atomic"
"time"
@@ -103,6 +104,22 @@ type jsonRequest struct {
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
// 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
@@ -129,6 +146,11 @@ type Client struct {
// POST mode.
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 sync.Mutex
@@ -659,6 +681,12 @@ out:
log.Infof("Reestablished connection to RPC server %s",
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
// has happened.
c.wsConn = wsConn
@@ -1332,3 +1360,84 @@ func (c *Client) Connect(tries int) error {
// All connection attempts failed, so return the last error.
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
}

View File

@@ -244,6 +244,43 @@ func (c *Client) Ping() error {
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
// GetPeerInfoAsync RPC invocation (or an applicable error).
type FutureGetPeerInfoResult chan *response

View File

@@ -15,6 +15,12 @@ import (
"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
// SignRawTransaction function accepts.
type SigHashType string
@@ -296,7 +302,31 @@ func (c *Client) SendRawTransactionAsync(tx *wire.MsgTx, allowHighFees bool) Fut
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)
}

View File

@@ -1,79 +0,0 @@
// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
//+build ignore
package main
import (
"bytes"
"io"
"log"
"os"
"strconv"
)
var (
start = []byte(`// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
// AUTOGENERATED by genalphabet.go; do not edit.
package base58
const (
// alphabet is the modified base58 alphabet used by Bitcoin.
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
alphabetIdx0 = '1'
)
var b58 = [256]byte{`)
end = []byte(`}`)
alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
tab = []byte("\t")
invalid = []byte("255")
comma = []byte(",")
space = []byte(" ")
nl = []byte("\n")
)
func write(w io.Writer, b []byte) {
_, err := w.Write(b)
if err != nil {
log.Fatal(err)
}
}
func main() {
fi, err := os.Create("alphabet.go")
if err != nil {
log.Fatal(err)
}
defer fi.Close()
write(fi, start)
write(fi, nl)
for i := byte(0); i < 32; i++ {
write(fi, tab)
for j := byte(0); j < 8; j++ {
idx := bytes.IndexByte(alphabet, i*8+j)
if idx == -1 {
write(fi, invalid)
} else {
write(fi, strconv.AppendInt(nil, int64(idx), 10))
}
write(fi, comma)
if j != 7 {
write(fi, space)
}
}
write(fi, nl)
}
write(fi, end)
write(fi, nl)
}

View File

@@ -10,18 +10,19 @@ datastore. Package bdb is licensed under the copyfree ISC license.
## Usage
This package is only a driver to the walletdb package and provides the database
type of "bdb". The only parameter the Open and Create functions take is the
database path as a string:
type of "bdb". The only parameters the Open and Create functions take is the
database path as a string, and an option for the database to not sync its
freelist to disk as a bool:
```Go
db, err := walletdb.Open("bdb", "path/to/database.db")
db, err := walletdb.Open("bdb", "path/to/database.db", true)
if err != nil {
// Handle error
}
```
```Go
db, err := walletdb.Create("bdb", "path/to/database.db")
db, err := walletdb.Create("bdb", "path/to/database.db", true)
if err != nil {
// Handle error
}

View File

@@ -339,7 +339,7 @@ func fileExists(name string) bool {
// openDB opens the database at the provided path. walletdb.ErrDbDoesNotExist
// is returned if the database doesn't exist and the create flag is not set.
func openDB(dbPath string, create bool) (walletdb.DB, error) {
func openDB(dbPath string, noFreelistSync bool, create bool) (walletdb.DB, error) {
if !create && !fileExists(dbPath) {
return nil, walletdb.ErrDbDoesNotExist
}
@@ -347,7 +347,7 @@ func openDB(dbPath string, create bool) (walletdb.DB, error) {
// Specify bbolt freelist options to reduce heap pressure in case the
// freelist grows to be very large.
options := &bbolt.Options{
NoFreelistSync: true,
NoFreelistSync: noFreelistSync,
FreelistType: bbolt.FreelistMapType,
}

View File

@@ -9,15 +9,16 @@ datastore.
Usage
This package is only a driver to the walletdb package and provides the database
type of "bdb". The only parameter the Open and Create functions take is the
database path as a string:
type of "bdb". The only parameters the Open and Create functions take is the
database path as a string, and an option for the database to not sync its
freelist to disk as a bool:
db, err := walletdb.Open("bdb", "path/to/database.db")
db, err := walletdb.Open("bdb", "path/to/database.db", true)
if err != nil {
// Handle error
}
db, err := walletdb.Create("bdb", "path/to/database.db")
db, err := walletdb.Create("bdb", "path/to/database.db", true)
if err != nil {
// Handle error
}

View File

@@ -15,41 +15,50 @@ const (
)
// parseArgs parses the arguments from the walletdb Open/Create methods.
func parseArgs(funcName string, args ...interface{}) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("invalid arguments to %s.%s -- "+
"expected database path", dbType, funcName)
func parseArgs(funcName string, args ...interface{}) (string, bool, error) {
if len(args) != 2 {
return "", false, fmt.Errorf("invalid arguments to %s.%s -- "+
"expected database path and no-freelist-sync option",
dbType, funcName)
}
dbPath, ok := args[0].(string)
if !ok {
return "", fmt.Errorf("first argument to %s.%s is invalid -- "+
"expected database path string", dbType, funcName)
return "", false, fmt.Errorf("first argument to %s.%s is "+
"invalid -- expected database path string", dbType,
funcName)
}
return dbPath, nil
noFreelistSync, ok := args[1].(bool)
if !ok {
return "", false, fmt.Errorf("second argument to %s.%s is "+
"invalid -- expected no-freelist-sync bool", dbType,
funcName)
}
return dbPath, noFreelistSync, nil
}
// openDBDriver is the callback provided during driver registration that opens
// an existing database for use.
func openDBDriver(args ...interface{}) (walletdb.DB, error) {
dbPath, err := parseArgs("Open", args...)
dbPath, noFreelistSync, err := parseArgs("Open", args...)
if err != nil {
return nil, err
}
return openDB(dbPath, false)
return openDB(dbPath, noFreelistSync, false)
}
// createDBDriver is the callback provided during driver registration that
// creates, initializes, and opens a database for use.
func createDBDriver(args ...interface{}) (walletdb.DB, error) {
dbPath, err := parseArgs("Create", args...)
dbPath, noFreelistSync, err := parseArgs("Create", args...)
if err != nil {
return nil, err
}
return openDB(dbPath, true)
return openDB(dbPath, noFreelistSync, true)
}
func init() {