Compare commits

...

50 commits
v1.0.2 ... lbry

Author SHA1 Message Date
Roy Lee
58e45d9641 remove psbt/go.sum as well 2021-09-11 20:49:56 -07:00
Brannon King
eb49498a52 remove pbst submodule 2021-09-10 17:02:02 -04:00
Brannon King
e72f99ac3f renamed package to lbcutil, updated refs to it 2021-09-10 16:37:45 -04:00
Roy Lee
78a0164ba2 update go imports 2021-09-10 16:37:22 -04:00
Roy Lee
1ccefad217 go module: update import path 2021-09-10 16:37:22 -04:00
Roy Lee
e3bdf5aa33 lbry: enlarge MaxSatoshi from 2e6 to 2e9 2021-09-10 16:37:22 -04:00
Olaoluwa Osuntokun
e2ba6805a8
Merge pull request #198 from guggero/stack-overflow-fix
Fix infinite recursion when printing error
2021-05-27 10:08:13 -07:00
Oliver Gugger
4ebb6a9960
address: fix stack overflow bug when printing error
Commit 24e673ae introduced a bug that cause the Error() function to
call itself recursively forever, causing a stack overflow. We explicitly
cast the error to its base type to avoid the recursion and add a small
test case that would've triggered the bug before.
2021-05-27 10:08:03 +02:00
Oliver Gugger
90ffd449a4
mod: update go.sum for golang 1.16.x
The version 1.16 of golang is more diligent when it comes to the go.sum
file and seems to always check whether all dependencies are contained.
Previous versions seem to have ignored this. This change should be
backward compatible though so we might as well commit it.
2021-05-27 10:06:01 +02:00
Olaoluwa Osuntokun
faeebcb9ab
Merge pull request #196 from Crypt-iQ/psbt_panic_fix_05142021
psbt: bounds check SumUtxoInputValues with NonWitness.TxOut indexing
2021-05-14 16:40:26 -07:00
eugene
9c91ffc684
psbt: bounds check SumUtxoInputValues with NonWitness.TxOut indexing
Otherwise, a malformed packet would panic on this check since the
NonWitness.TxOut field did not have the required TxOuts necessary.
2021-05-14 12:23:16 -04:00
Josh Bleecher Snyder
a53e38424c base58: allocate less in Encode
* calculate maximum output length more precisely
  to avoid allocation in the append
* use big.Int.Sign instead of needing bigZero

name                 old time/op    new time/op    delta
Base58Encode_5K-8      5.86ms ± 3%    5.79ms ± 2%   -1.27%  (p=0.035 n=9+10)
Base58Encode_100K-8     2.23s ± 1%     2.23s ± 0%     ~     (p=0.074 n=9+8)
Base58Decode_5K-8       281µs ± 1%     282µs ± 1%     ~     (p=0.720 n=9+10)
Base58Decode_100K-8    89.4ms ± 7%    88.3ms ± 7%     ~     (p=0.123 n=10+10)

name                 old speed      new speed      delta
Base58Encode_5K-8     854kB/s ± 3%   864kB/s ± 2%     ~     (p=0.134 n=9+10)
Base58Encode_100K-8  40.0kB/s ± 0%  40.0kB/s ± 0%     ~     (all equal)
Base58Decode_5K-8    24.3MB/s ± 1%  24.2MB/s ± 1%     ~     (p=0.644 n=9+10)
Base58Decode_100K-8  1.53MB/s ± 7%  1.55MB/s ± 7%     ~     (p=0.218 n=10+10)

name                 old alloc/op   new alloc/op   delta
Base58Encode_5K-8      28.7kB ± 0%    19.2kB ± 0%  -33.03%  (p=0.000 n=10+10)
Base58Encode_100K-8     557kB ± 0%     385kB ± 0%  -30.88%  (p=0.000 n=10+10)
Base58Decode_5K-8       349kB ± 0%     349kB ± 0%     ~     (all equal)
Base58Decode_100K-8     133MB ± 0%     133MB ± 0%     ~     (p=0.183 n=10+10)

name                 old allocs/op  new allocs/op  delta
Base58Encode_5K-8        5.00 ± 0%      4.00 ± 0%  -20.00%  (p=0.000 n=10+10)
Base58Encode_100K-8      5.00 ± 0%      4.00 ± 0%  -20.00%  (p=0.000 n=10+10)
Base58Decode_5K-8         129 ± 0%       129 ± 0%     ~     (all equal)
Base58Decode_100K-8     2.51k ± 0%     2.51k ± 0%     ~     (p=0.321 n=10+10)

When Go 1.16 is released, performance will improve
significantly due to improvements to math/big.Int's division implementation.
2020-12-08 09:37:02 -05:00
Dave Collins
d63d9f2b44 bech32: Add base256 conversion convenience funcs.
Since bech32 itself works with data encoded with 5 bits per byte (aka
base32) padded out to the nearest byte boundary, the existing functions
for Encode and Decode accept and return data encoded that way.

However, the most common way to use bech32 is to encode data that is
already encoded with 8 bits per byte (aka base256) without padding which
means it is up to the caller to use the ConvertBits function properly to
convert between the two encodings.

Consequently, this introduces two convenience functions for working
directly with base256-encoded data named EncodeFromBase256 and
DecodeToBase256 along with a full set of tests to ensure they work
expected.
2020-12-01 09:42:36 -05:00
Dave Collins
36377a3c8c bech32: Ensure HRP is lowercase when encoding.
BIP173 specifically calls out that encoders must always output an all
lowercase bech32 string and that the lowercase form is used when
determining a character's value for calculating the checksum.

Currently, the implementation does not respect either of those
requirements.

This modifies the Encode function to convert the provided HRP to
lowercase to ensure the requirements are satisfied and adds tests
accordingly.
2020-12-01 09:42:36 -05:00
Anirudha Bose
f281d151bb bech32: back port improvements from decred/dcrd@9b88dd0
This commit brings a host of improvements to the bech32 package. The
public interface of the package remains unchanged.

Summary of changes:
* Improved error handling using dedicated error types. Programmatically
  detect if the errors produced are the expected ones.
* Improve test coverage to test more corner cases. Added test vectors
  from Bitcoin Core.
* Add a benchmark for a full encode/decode cycle of a bech32 string.
* Add a new function DecodeNoLimit, for decoding large bech32 encoded
  strings. It does NOT validate against the BIP-173 maximum length
  allowed for bech32 strings.
* Automatically convert the HRP to lowercase in Encode function.
* Improve performance of encode/decode functions by using
  strings.Builder.
* Improve memory allocation in ConvertBits function.
* Updated documentation.

Credits: @matheusd

Closes #152 and #168.
2020-12-01 09:42:36 -05:00
Egon Elbre
4031bdc69d base58: add new testcases from github.com/bitcoin 2020-11-24 13:21:44 -05:00
Egon Elbre
594180da5d base58: optimize Decode
Before:
    BenchmarkBase58Decode_5K-32     266      4373774 ns/op  1.56 MB/s
    BenchmarkBase58Decode_100K-32   1     1516196700 ns/op  0.09 MB/s

After:
    BenchmarkBase58Decode_5K-32     3868      277944 ns/op  24.57 MB/s
    BenchmarkBase58Decode_100K-32   13      83772100 ns/op   1.63 MB/s
2020-11-24 13:21:44 -05:00
Egon Elbre
ed1fc7ad99 base58: optimize Encode
Before:
    BenchmarkBase58Encode_5K-32     46      23934763 ns/op  0.21 MB/s
    BenchmarkBase58Encode_100K-32    1    9351948600 ns/op  0.01 MB/s

After:
    BenchmarkBase58Encode_5K-32    501       2419129 ns/op  2.07 MB/s
    BenchmarkBase58Encode_100K-32    2     923507950 ns/op  0.11 MB/s
2020-11-24 13:21:44 -05:00
Olaoluwa Osuntokun
a21f014935
Merge pull request #182 from lightning-signer/bip32-zeros
Correct BIP-32 derivation issue
2020-11-03 16:44:01 -08:00
David Hill
88fd8b3dc6 go.mod: bump to go 1.14, latest supported version 2020-10-26 09:48:59 -04:00
David Hill
d32feb0a8e build: replace travis with github ci 2020-10-26 09:48:59 -04:00
Devrandom
dde9e31e50 hdkeychain: correct BIP-32 derivation issue
fixes issue #172
2020-10-21 13:21:55 +02:00
Pascal S. de Kloe
24e673ae72 FIX: integers incorrectly encoded as a rune with append. Go no longer allows it. 2020-10-15 09:23:55 -04:00
Anirudha Bose
063c4115b3 hdkeychain: add CloneWithVersion to set custom HD version bytes
This adds a new method to the ExtendedKey type that allows cloning the
extended key with custom HD version bytes. It does not mutate the
original extended key on which the method is called.

Added some tests to demonstrate the utility of this method, i.e.,
conversion between standard and SLIP-0132 extended keys.
2020-09-21 09:54:55 -04:00
gipsy
4232759481 Tiny grammar correction
This function should only `by` used by applications that need to create custom ExtendedKeys. => This function should only `be` used by applications that need to create custom ExtendedKeys
2020-08-31 09:38:46 -04:00
Olaoluwa Osuntokun
5f93e33af2
Merge pull request #178 from guggero/psbt-vuln-fix
psbt: restore compatibility with wallets that patch CVE-2020-14199
2020-08-26 12:48:09 -07:00
Oliver Gugger
afbd53ee7e
psbt: test full scenario of CVE-2020-14199 patched wallet
We add a test that makes sure the full signing scenario of a wallet that
has the CVE-2020-14199 vulnerability patched is supported by this
library.
2020-07-20 15:02:06 +02:00
Oliver Gugger
c7b6a5aace
psbt: also check witness UTXO if both are set
A wallet that has patched the CVE-2020-14199 vulnerability will always
include a non-witness UTXO, even for witness inputs. In the signer, we
detect that the input we spend is a witness input and copy over the
TxOut to the witness UTXO field. Therefore it is possible that both UTXO
fields are set at the same time. We need to adjust the sanity checks
when adding a partial signature to account for that.
2020-07-20 15:02:05 +02:00
Oliver Gugger
b283b0eb92
psbt: don't remove non-witness UTXO for segwit v0
As a countermeasure to CVE-2020-14199 new HW wallet firmwares require
the full non-witness UTXO to be set even for witness inputs.
We therefore shouldn't remove it when signing.
2020-07-20 15:02:03 +02:00
Oliver Gugger
c5f199e40f
psbt: remove UTXO sanity check to allow fix for CVE
As described in CVE-2020-14199 it is unsafe to only rely on witness
UTXO information when signing. Hardware wallets fixed this by also
requiring the full non-witness UTXO to be present for a witness input.
To be compatible with those newer hardware wallet firmware, we need to
remove the sanity checks that disallowed setting witness and non-witness
UTXOs at the same time.
See https://github.com/bitcoin/bitcoin/pull/19215 for comparison which
removed the sanity checks in Bitcoin Core.
2020-07-20 15:02:02 +02:00
michael1011
4649e4b73b add test case for litecoin bech32 addresses 2020-07-13 09:59:11 -04:00
Anirudha Bose
f648594deb hdkeychain: Fix small wording issue in ChainCode() tests 2020-07-13 09:53:07 -04:00
Anirudha Bose
6c6f3fd3b7 hdkeychain: Remove duplicate ChildNum() method 2020-07-13 09:53:07 -04:00
Marko Bencun
5fadf96a72 hdkeychain: extend API with ChainCode(), ChildNum()
No way to access them otherwise. Handy for interoperability.
2020-07-13 09:53:07 -04:00
Anirudha Bose
c53e27f6f1 Fix OutOfRangeError checks in block_test.go 2020-07-13 09:48:38 -04:00
Yuchuan
e3017c9aab Update block.go
Fix bound check in block.tx(txNum int)
2020-07-13 09:48:38 -04:00
Kalle Rosenbaum
0af7fd2595 Assign returned values in correct order
This is basically a copy of PR #154, which is now obsolete due to refactorings. It also adds a test case for this issue.
2020-07-13 09:45:52 -04:00
Steven Roose
4443e04cb8 Fix error in base58check test 2020-07-13 09:35:42 -04:00
Anirudha Bose
6065135ba8 Improve test coverage of WIF decoder/encoder
Use subtests to split cases, and add new ones, notably for decoding
invalid WIFs.
2020-07-06 10:32:46 -04:00
shuai.qi
c78a7129bf Fix typo 2020-07-06 10:08:39 -04:00
johnta0
35f6653e0a hdkeychain: fix trivial typo 2020-07-06 10:08:01 -04:00
Akio Nakamura
63e5e276cd Fix some typos in docs
This PR fixes 'hardended'/'hardned' to 'hardened' in the godocs.
2020-07-06 10:06:32 -04:00
Olaoluwa Osuntokun
af92bbf499
Merge pull request #173 from guggero/psbt-util
psbt: add/export new utility functions and BIP 69 in-place sort
2020-06-25 00:45:29 -07:00
Oliver Gugger
0b85b11dcc
psbt: add BIP 69 in-place sort 2020-06-25 09:38:04 +02:00
Oliver Gugger
488d2cc834
psbt: add new utility functions 2020-06-25 09:38:03 +02:00
Oliver Gugger
8ec8bad266
psbt: export WriteTxWitness 2020-06-25 09:38:03 +02:00
Olaoluwa Osuntokun
7ddbb930fd
Merge pull request #165 from onyb/has-witness-nil-deference
Fix nil pointer dereference when WitnessHash is called before HasWitness
2020-06-22 16:30:30 -07:00
Olaoluwa Osuntokun
3beec01267
Merge pull request #171 from wpaulino/expose-extended-key-fields
hdkeychain: expose extended key's version and child index
2020-06-22 16:27:57 -07:00
Wilmer Paulino
d8c8794021
hdkeychain: expose extended key's version and child index 2020-06-17 16:31:20 -07:00
Anirudha Bose
29af078e7b
Fix nil pointer dereference when WitnessHash is called before HasWitness
Issue: btcsuite/btcd#1543
Related PR: btcsuite/btcutil#156
2020-05-05 09:28:57 +05:30
83 changed files with 3466 additions and 1066 deletions

27
.github/workflows/go.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Build and Test
on: [push, pull_request]
jobs:
build:
name: Go CI
runs-on: ubuntu-latest
strategy:
matrix:
go: [1.16]
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Check out source
uses: actions/checkout@v2
- name: Install Linters
run: "curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.31.0"
- name: Build
run: go build ./...
- name: Test
run: |
sh ./goclean.sh
- name: Send lbcutil coverage
uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: profile.cov

View file

@ -1,15 +0,0 @@
language: go
go:
- "1.9.4"
- "1.10"
sudo: false
install:
- go get -d -t -v ./...
- go get -v github.com/alecthomas/gometalinter
- gometalinter --install
script:
- export PATH=$PATH:$HOME/gopath/bin
- ./goclean.sh
after_success:
- go get -v github.com/mattn/goveralls
- goveralls -coverprofile=profile.cov -service=travis-ci

View file

@ -1,50 +1,11 @@
btcutil
lbcutil
=======
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
[![Coverage Status](http://img.shields.io/coveralls/btcsuite/btcutil.svg)](https://coveralls.io/r/btcsuite/btcutil?branch=master)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcutil)
Package btcutil provides bitcoin-specific convenience functions and types.
A comprehensive suite of tests is provided to ensure proper functionality. See
`test_coverage.txt` for the gocov coverage report. Alternatively, if you are
running a POSIX OS, you can run the `cov_report.sh` script for a real-time
report.
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
Package lbcutil provides convenience functions and types.
This package was developed for btcd, an alternative full-node implementation of
bitcoin which is under active development by Conformal. Although it was
primarily written for btcd, this package has intentionally been designed so it
can be used as a standalone package for any projects needing the functionality
provided.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil
```
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from the btcsuite developers. To
verify the signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package btcutil is licensed under the [copyfree](http://copyfree.org) ISC
License.
provided. It has been modified to support lbcd.

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
import (
"bytes"
@ -11,10 +11,10 @@ import (
"fmt"
"strings"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcutil/base58"
"github.com/btcsuite/btcutil/bech32"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcutil/base58"
"github.com/lbryio/lbcutil/bech32"
"golang.org/x/crypto/ripemd160"
)
@ -23,7 +23,7 @@ import (
type UnsupportedWitnessVerError byte
func (e UnsupportedWitnessVerError) Error() string {
return "unsupported witness version: " + string(e)
return fmt.Sprintf("unsupported witness version: %#x", byte(e))
}
// UnsupportedWitnessProgLenError describes an error where a segwit address
@ -31,7 +31,7 @@ func (e UnsupportedWitnessVerError) Error() string {
type UnsupportedWitnessProgLenError int
func (e UnsupportedWitnessProgLenError) Error() string {
return "unsupported witness program length: " + string(e)
return fmt.Sprintf("unsupported witness program length: %d", int(e))
}
var (

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil_test
package lbcutil_test
import (
"bytes"
@ -12,26 +12,33 @@ import (
"strings"
"testing"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
"golang.org/x/crypto/ripemd160"
)
type CustomParamStruct struct {
Net wire.BitcoinNet
PubKeyHashAddrID byte
ScriptHashAddrID byte
Bech32HRPSegwit string
}
var CustomParams = CustomParamStruct{
PubKeyHashAddrID: 0x30, // starts with L
ScriptHashAddrID: 0x32, // starts with M
Net: 0xdbb6c0fb, // litecoin mainnet HD version bytes
PubKeyHashAddrID: 0x30, // starts with L
ScriptHashAddrID: 0x32, // starts with M
Bech32HRPSegwit: "ltc", // starts with ltc
}
// We use this function to be able to test functionality in DecodeAddress for
// defaultNet addresses
func applyCustomParams(params chaincfg.Params, customParams CustomParamStruct) chaincfg.Params {
params.Net = customParams.Net
params.PubKeyHashAddrID = customParams.PubKeyHashAddrID
params.ScriptHashAddrID = customParams.ScriptHashAddrID
params.Bech32HRPSegwit = customParams.Bech32HRPSegwit
return params
}
@ -43,8 +50,8 @@ func TestAddresses(t *testing.T) {
addr string
encoded string
valid bool
result btcutil.Address
f func() (btcutil.Address, error)
result lbcutil.Address
f func() (lbcutil.Address, error)
net *chaincfg.Params
}{
// Positive P2PKH tests.
@ -53,16 +60,16 @@ func TestAddresses(t *testing.T) {
addr: "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX",
encoded: "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX",
valid: true,
result: btcutil.TstAddressPubKeyHash(
result: lbcutil.TstAddressPubKeyHash(
[ripemd160.Size]byte{
0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84},
chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84}
return btcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
return lbcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -71,16 +78,16 @@ func TestAddresses(t *testing.T) {
addr: "12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG",
encoded: "12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG",
valid: true,
result: btcutil.TstAddressPubKeyHash(
result: lbcutil.TstAddressPubKeyHash(
[ripemd160.Size]byte{
0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4,
0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa},
chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4,
0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa}
return btcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
return lbcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -89,16 +96,16 @@ func TestAddresses(t *testing.T) {
addr: "LM2WMpR1Rp6j3Sa59cMXMs1SPzj9eXpGc1",
encoded: "LM2WMpR1Rp6j3Sa59cMXMs1SPzj9eXpGc1",
valid: true,
result: btcutil.TstAddressPubKeyHash(
result: lbcutil.TstAddressPubKeyHash(
[ripemd160.Size]byte{
0x13, 0xc6, 0x0d, 0x8e, 0x68, 0xd7, 0x34, 0x9f, 0x5b, 0x4c,
0xa3, 0x62, 0xc3, 0x95, 0x4b, 0x15, 0x04, 0x50, 0x61, 0xb1},
CustomParams.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0x13, 0xc6, 0x0d, 0x8e, 0x68, 0xd7, 0x34, 0x9f, 0x5b, 0x4c,
0xa3, 0x62, 0xc3, 0x95, 0x4b, 0x15, 0x04, 0x50, 0x61, 0xb1}
return btcutil.NewAddressPubKeyHash(pkHash, &customParams)
return lbcutil.NewAddressPubKeyHash(pkHash, &customParams)
},
net: &customParams,
},
@ -107,16 +114,16 @@ func TestAddresses(t *testing.T) {
addr: "mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz",
encoded: "mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz",
valid: true,
result: btcutil.TstAddressPubKeyHash(
result: lbcutil.TstAddressPubKeyHash(
[ripemd160.Size]byte{
0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83,
0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f},
chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83,
0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f}
return btcutil.NewAddressPubKeyHash(pkHash, &chaincfg.TestNet3Params)
return lbcutil.NewAddressPubKeyHash(pkHash, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -126,12 +133,12 @@ func TestAddresses(t *testing.T) {
name: "p2pkh wrong hash length",
addr: "",
valid: false,
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0x00, 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b,
0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad,
0xaa}
return btcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
return lbcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -151,12 +158,12 @@ func TestAddresses(t *testing.T) {
addr: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC",
encoded: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC",
valid: true,
result: btcutil.TstAddressScriptHash(
result: lbcutil.TstAddressScriptHash(
[ripemd160.Size]byte{
0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9, 0xf2,
0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55, 0x10},
chaincfg.MainNetParams.ScriptHashAddrID),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
script := []byte{
0x52, 0x41, 0x04, 0x91, 0xbb, 0xa2, 0x51, 0x09, 0x12, 0xa5,
0xbd, 0x37, 0xda, 0x1f, 0xb5, 0xb1, 0x67, 0x30, 0x10, 0xe4,
@ -179,7 +186,7 @@ func TestAddresses(t *testing.T) {
0xdb, 0xfb, 0x1e, 0x75, 0x4e, 0x35, 0xfa, 0x1c, 0x78, 0x44,
0xc4, 0x1f, 0x32, 0x2a, 0x18, 0x63, 0xd4, 0x62, 0x13, 0x53,
0xae}
return btcutil.NewAddressScriptHash(script, &chaincfg.MainNetParams)
return lbcutil.NewAddressScriptHash(script, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -188,16 +195,16 @@ func TestAddresses(t *testing.T) {
addr: "MVcg9uEvtWuP5N6V48EHfEtbz48qR8TKZ9",
encoded: "MVcg9uEvtWuP5N6V48EHfEtbz48qR8TKZ9",
valid: true,
result: btcutil.TstAddressScriptHash(
result: lbcutil.TstAddressScriptHash(
[ripemd160.Size]byte{
0xee, 0x34, 0xac, 0x67, 0x6b, 0xda, 0xf6, 0xe3, 0x70, 0xc8,
0xc8, 0x20, 0xb9, 0x48, 0xed, 0xfa, 0xd3, 0xa8, 0x73, 0xd8},
CustomParams.ScriptHashAddrID),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0xEE, 0x34, 0xAC, 0x67, 0x6B, 0xDA, 0xF6, 0xE3, 0x70, 0xC8,
0xC8, 0x20, 0xB9, 0x48, 0xED, 0xFA, 0xD3, 0xA8, 0x73, 0xD8}
return btcutil.NewAddressScriptHashFromHash(pkHash, &customParams)
return lbcutil.NewAddressScriptHashFromHash(pkHash, &customParams)
},
net: &customParams,
},
@ -209,16 +216,16 @@ func TestAddresses(t *testing.T) {
addr: "3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8",
encoded: "3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8",
valid: true,
result: btcutil.TstAddressScriptHash(
result: lbcutil.TstAddressScriptHash(
[ripemd160.Size]byte{
0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37,
0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4},
chaincfg.MainNetParams.ScriptHashAddrID),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
hash := []byte{
0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37,
0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4}
return btcutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams)
return lbcutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -228,16 +235,16 @@ func TestAddresses(t *testing.T) {
addr: "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
encoded: "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
valid: true,
result: btcutil.TstAddressScriptHash(
result: lbcutil.TstAddressScriptHash(
[ripemd160.Size]byte{
0xc5, 0x79, 0x34, 0x2c, 0x2c, 0x4c, 0x92, 0x20, 0x20, 0x5e,
0x2c, 0xdc, 0x28, 0x56, 0x17, 0x04, 0x0c, 0x92, 0x4a, 0x0a},
chaincfg.TestNet3Params.ScriptHashAddrID),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
hash := []byte{
0xc5, 0x79, 0x34, 0x2c, 0x2c, 0x4c, 0x92, 0x20, 0x20, 0x5e,
0x2c, 0xdc, 0x28, 0x56, 0x17, 0x04, 0x0c, 0x92, 0x4a, 0x0a}
return btcutil.NewAddressScriptHashFromHash(hash, &chaincfg.TestNet3Params)
return lbcutil.NewAddressScriptHashFromHash(hash, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -247,12 +254,12 @@ func TestAddresses(t *testing.T) {
name: "p2sh wrong hash length",
addr: "",
valid: false,
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
hash := []byte{
0x00, 0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9,
0xf2, 0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55,
0x10}
return btcutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams)
return lbcutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -263,20 +270,20 @@ func TestAddresses(t *testing.T) {
addr: "02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4",
encoded: "13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
0x52, 0xc6, 0xb4},
btcutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
0x52, 0xc6, 0xb4}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -285,20 +292,20 @@ func TestAddresses(t *testing.T) {
addr: "03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65",
encoded: "15sHANNUBSh6nDp8XkDPmQcW6n3EFwmvE6",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
0xb1, 0x6e, 0x65},
btcutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
0xb1, 0x6e, 0x65}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -308,7 +315,7 @@ func TestAddresses(t *testing.T) {
"e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
encoded: "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
@ -317,8 +324,8 @@ func TestAddresses(t *testing.T) {
0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
0xf6, 0x56, 0xb4, 0x12, 0xa3},
btcutil.PKFUncompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFUncompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
@ -327,7 +334,7 @@ func TestAddresses(t *testing.T) {
0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
0xf6, 0x56, 0xb4, 0x12, 0xa3}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -337,7 +344,7 @@ func TestAddresses(t *testing.T) {
"0d45264838c0bd96852662ce6a847b197376830160c6d2eb5e6a4c44d33f453e",
encoded: "1Ja5rs7XBZnK88EuLVcFqYGMEbBitzchmX",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x06, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
@ -346,8 +353,8 @@ func TestAddresses(t *testing.T) {
0x96, 0x85, 0x26, 0x62, 0xce, 0x6a, 0x84, 0x7b, 0x19, 0x73,
0x76, 0x83, 0x01, 0x60, 0xc6, 0xd2, 0xeb, 0x5e, 0x6a, 0x4c,
0x44, 0xd3, 0x3f, 0x45, 0x3e},
btcutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x06, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
@ -356,7 +363,7 @@ func TestAddresses(t *testing.T) {
0x96, 0x85, 0x26, 0x62, 0xce, 0x6a, 0x84, 0x7b, 0x19, 0x73,
0x76, 0x83, 0x01, 0x60, 0xc6, 0xd2, 0xeb, 0x5e, 0x6a, 0x4c,
0x44, 0xd3, 0x3f, 0x45, 0x3e}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -366,7 +373,7 @@ func TestAddresses(t *testing.T) {
"37a576782eba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c1e0908ef7b",
encoded: "1ExqMmf6yMxcBMzHjbj41wbqYuqoX6uBLG",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x07, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
@ -375,8 +382,8 @@ func TestAddresses(t *testing.T) {
0x8a, 0x7e, 0xf8, 0xbd, 0x3b, 0x3c, 0xfb, 0x1e, 0xdb, 0x71,
0x17, 0xab, 0x65, 0x12, 0x9b, 0x8a, 0x2e, 0x68, 0x1f, 0x3c,
0x1e, 0x09, 0x08, 0xef, 0x7b},
btcutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x07, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
@ -385,7 +392,7 @@ func TestAddresses(t *testing.T) {
0x8a, 0x7e, 0xf8, 0xbd, 0x3b, 0x3c, 0xfb, 0x1e, 0xdb, 0x71,
0x17, 0xab, 0x65, 0x12, 0x9b, 0x8a, 0x2e, 0x68, 0x1f, 0x3c,
0x1e, 0x09, 0x08, 0xef, 0x7b}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -394,20 +401,20 @@ func TestAddresses(t *testing.T) {
addr: "02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4",
encoded: "mhiDPVP2nJunaAgTjzWSHCYfAqxxrxzjmo",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
0x52, 0xc6, 0xb4},
btcutil.PKFCompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFCompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
0x52, 0xc6, 0xb4}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -416,20 +423,20 @@ func TestAddresses(t *testing.T) {
addr: "03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65",
encoded: "mkPETRTSzU8MZLHkFKBmbKppxmdw9qT42t",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
0xb1, 0x6e, 0x65},
btcutil.PKFCompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFCompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
0xb1, 0x6e, 0x65}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -439,7 +446,7 @@ func TestAddresses(t *testing.T) {
"cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
encoded: "mh8YhPYEAYs3E7EVyKtB5xrcfMExkkdEMF",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
@ -448,8 +455,8 @@ func TestAddresses(t *testing.T) {
0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
0xf6, 0x56, 0xb4, 0x12, 0xa3},
btcutil.PKFUncompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFUncompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
@ -458,7 +465,7 @@ func TestAddresses(t *testing.T) {
0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
0xf6, 0x56, 0xb4, 0x12, 0xa3}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -468,7 +475,7 @@ func TestAddresses(t *testing.T) {
"40d45264838c0bd96852662ce6a847b197376830160c6d2eb5e6a4c44d33f453e",
encoded: "my639vCVzbDZuEiX44adfTUg6anRomZLEP",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x06, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
@ -477,8 +484,8 @@ func TestAddresses(t *testing.T) {
0x96, 0x85, 0x26, 0x62, 0xce, 0x6a, 0x84, 0x7b, 0x19, 0x73,
0x76, 0x83, 0x01, 0x60, 0xc6, 0xd2, 0xeb, 0x5e, 0x6a, 0x4c,
0x44, 0xd3, 0x3f, 0x45, 0x3e},
btcutil.PKFHybrid, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFHybrid, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x06, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
@ -487,7 +494,7 @@ func TestAddresses(t *testing.T) {
0x96, 0x85, 0x26, 0x62, 0xce, 0x6a, 0x84, 0x7b, 0x19, 0x73,
0x76, 0x83, 0x01, 0x60, 0xc6, 0xd2, 0xeb, 0x5e, 0x6a, 0x4c,
0x44, 0xd3, 0x3f, 0x45, 0x3e}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -497,7 +504,7 @@ func TestAddresses(t *testing.T) {
"537a576782eba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c1e0908ef7b",
encoded: "muUnepk5nPPrxUTuTAhRqrpAQuSWS5fVii",
valid: true,
result: btcutil.TstAddressPubKey(
result: lbcutil.TstAddressPubKey(
[]byte{
0x07, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
@ -506,8 +513,8 @@ func TestAddresses(t *testing.T) {
0x8a, 0x7e, 0xf8, 0xbd, 0x3b, 0x3c, 0xfb, 0x1e, 0xdb, 0x71,
0x17, 0xab, 0x65, 0x12, 0x9b, 0x8a, 0x2e, 0x68, 0x1f, 0x3c,
0x1e, 0x09, 0x08, 0xef, 0x7b},
btcutil.PKFHybrid, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (btcutil.Address, error) {
lbcutil.PKFHybrid, chaincfg.TestNet3Params.PubKeyHashAddrID),
f: func() (lbcutil.Address, error) {
serializedPubKey := []byte{
0x07, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
@ -516,7 +523,7 @@ func TestAddresses(t *testing.T) {
0x8a, 0x7e, 0xf8, 0xbd, 0x3b, 0x3c, 0xfb, 0x1e, 0xdb, 0x71,
0x17, 0xab, 0x65, 0x12, 0x9b, 0x8a, 0x2e, 0x68, 0x1f, 0x3c,
0x1e, 0x09, 0x08, 0xef, 0x7b}
return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
return lbcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -526,17 +533,17 @@ func TestAddresses(t *testing.T) {
addr: "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
encoded: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
valid: true,
result: btcutil.TstAddressWitnessPubKeyHash(
result: lbcutil.TstAddressWitnessPubKeyHash(
0,
[20]byte{
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
chaincfg.MainNetParams.Bech32HRPSegwit),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
return btcutil.NewAddressWitnessPubKeyHash(pkHash, &chaincfg.MainNetParams)
return lbcutil.NewAddressWitnessPubKeyHash(pkHash, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -545,7 +552,7 @@ func TestAddresses(t *testing.T) {
addr: "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3",
encoded: "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3",
valid: true,
result: btcutil.TstAddressWitnessScriptHash(
result: lbcutil.TstAddressWitnessScriptHash(
0,
[32]byte{
0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
@ -553,13 +560,13 @@ func TestAddresses(t *testing.T) {
0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
chaincfg.MainNetParams.Bech32HRPSegwit),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
scriptHash := []byte{
0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
return btcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.MainNetParams)
return lbcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
@ -568,17 +575,17 @@ func TestAddresses(t *testing.T) {
addr: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
encoded: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
valid: true,
result: btcutil.TstAddressWitnessPubKeyHash(
result: lbcutil.TstAddressWitnessPubKeyHash(
0,
[20]byte{
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
chaincfg.TestNet3Params.Bech32HRPSegwit),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
return btcutil.NewAddressWitnessPubKeyHash(pkHash, &chaincfg.TestNet3Params)
return lbcutil.NewAddressWitnessPubKeyHash(pkHash, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -587,7 +594,7 @@ func TestAddresses(t *testing.T) {
addr: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
encoded: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
valid: true,
result: btcutil.TstAddressWitnessScriptHash(
result: lbcutil.TstAddressWitnessScriptHash(
0,
[32]byte{
0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
@ -595,13 +602,13 @@ func TestAddresses(t *testing.T) {
0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
chaincfg.TestNet3Params.Bech32HRPSegwit),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
scriptHash := []byte{
0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
return btcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.TestNet3Params)
return lbcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
@ -610,7 +617,7 @@ func TestAddresses(t *testing.T) {
addr: "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
encoded: "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
valid: true,
result: btcutil.TstAddressWitnessScriptHash(
result: lbcutil.TstAddressWitnessScriptHash(
0,
[32]byte{
0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
@ -618,16 +625,36 @@ func TestAddresses(t *testing.T) {
0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33},
chaincfg.TestNet3Params.Bech32HRPSegwit),
f: func() (btcutil.Address, error) {
f: func() (lbcutil.Address, error) {
scriptHash := []byte{
0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}
return btcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.TestNet3Params)
return lbcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.TestNet3Params)
},
net: &chaincfg.TestNet3Params,
},
{
name: "segwit litecoin mainnet p2wpkh v0",
addr: "LTC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KGMN4N9",
encoded: "ltc1qw508d6qejxtdg4y5r3zarvary0c5xw7kgmn4n9",
valid: true,
result: lbcutil.TstAddressWitnessPubKeyHash(
0,
[20]byte{
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
CustomParams.Bech32HRPSegwit,
),
f: func() (lbcutil.Address, error) {
pkHash := []byte{
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
return lbcutil.NewAddressWitnessPubKeyHash(pkHash, &customParams)
},
net: &customParams,
},
// Unsupported witness versions (version 0 only supported at this point)
{
name: "segwit mainnet witness v1",
@ -704,9 +731,13 @@ func TestAddresses(t *testing.T) {
},
}
if err := chaincfg.Register(&customParams); err != nil {
panic(err)
}
for _, test := range tests {
// Decode addr and compare error against valid.
decoded, err := btcutil.DecodeAddress(test.addr, test.net)
decoded, err := lbcutil.DecodeAddress(test.addr, test.net)
if (err == nil) != test.valid {
t.Errorf("%v: decoding test failed: %v", test.name, err)
return
@ -743,20 +774,20 @@ func TestAddresses(t *testing.T) {
// Perform type-specific calculations.
var saddr []byte
switch d := decoded.(type) {
case *btcutil.AddressPubKeyHash:
saddr = btcutil.TstAddressSAddr(encoded)
case *lbcutil.AddressPubKeyHash:
saddr = lbcutil.TstAddressSAddr(encoded)
case *btcutil.AddressScriptHash:
saddr = btcutil.TstAddressSAddr(encoded)
case *lbcutil.AddressScriptHash:
saddr = lbcutil.TstAddressSAddr(encoded)
case *btcutil.AddressPubKey:
case *lbcutil.AddressPubKey:
// Ignore the error here since the script
// address is checked below.
saddr, _ = hex.DecodeString(d.String())
case *btcutil.AddressWitnessPubKeyHash:
saddr = btcutil.TstAddressSegwitSAddr(encoded)
case *btcutil.AddressWitnessScriptHash:
saddr = btcutil.TstAddressSegwitSAddr(encoded)
case *lbcutil.AddressWitnessPubKeyHash:
saddr = lbcutil.TstAddressSegwitSAddr(encoded)
case *lbcutil.AddressWitnessScriptHash:
saddr = lbcutil.TstAddressSegwitSAddr(encoded)
}
// Check script address, as well as the Hash160 method for P2PKH and
@ -767,28 +798,28 @@ func TestAddresses(t *testing.T) {
return
}
switch a := decoded.(type) {
case *btcutil.AddressPubKeyHash:
case *lbcutil.AddressPubKeyHash:
if h := a.Hash160()[:]; !bytes.Equal(saddr, h) {
t.Errorf("%v: hashes do not match:\n%x != \n%x",
test.name, saddr, h)
return
}
case *btcutil.AddressScriptHash:
case *lbcutil.AddressScriptHash:
if h := a.Hash160()[:]; !bytes.Equal(saddr, h) {
t.Errorf("%v: hashes do not match:\n%x != \n%x",
test.name, saddr, h)
return
}
case *btcutil.AddressWitnessPubKeyHash:
case *lbcutil.AddressWitnessPubKeyHash:
if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
t.Errorf("%v: hrps do not match:\n%x != \n%x",
test.name, test.net.Bech32HRPSegwit, hrp)
return
}
expVer := test.result.(*btcutil.AddressWitnessPubKeyHash).WitnessVersion()
expVer := test.result.(*lbcutil.AddressWitnessPubKeyHash).WitnessVersion()
if v := a.WitnessVersion(); v != expVer {
t.Errorf("%v: witness versions do not match:\n%x != \n%x",
test.name, expVer, v)
@ -801,14 +832,14 @@ func TestAddresses(t *testing.T) {
return
}
case *btcutil.AddressWitnessScriptHash:
case *lbcutil.AddressWitnessScriptHash:
if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
t.Errorf("%v: hrps do not match:\n%x != \n%x",
test.name, test.net.Bech32HRPSegwit, hrp)
return
}
expVer := test.result.(*btcutil.AddressWitnessScriptHash).WitnessVersion()
expVer := test.result.(*lbcutil.AddressWitnessScriptHash).WitnessVersion()
if v := a.WitnessVersion(); v != expVer {
t.Errorf("%v: witness versions do not match:\n%x != \n%x",
test.name, expVer, v)
@ -828,6 +859,14 @@ func TestAddresses(t *testing.T) {
test.name)
return
}
} else {
// If there is an error, make sure we can print it
// correctly.
errStr := err.Error()
if errStr == "" {
t.Errorf("%v: error was non-nil but message is"+
"empty: %v", test.name, err)
}
}
if !test.valid {

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
import (
"errors"
@ -29,23 +29,23 @@ const (
// String returns the unit as a string. For recognized units, the SI
// prefix is used, or "Satoshi" for the base unit. For all unrecognized
// units, "1eN BTC" is returned, where N is the AmountUnit.
// units, "1eN LBC" is returned, where N is the AmountUnit.
func (u AmountUnit) String() string {
switch u {
case AmountMegaBTC:
return "MBTC"
return "MLBC"
case AmountKiloBTC:
return "kBTC"
return "kLBC"
case AmountBTC:
return "BTC"
return "LBC"
case AmountMilliBTC:
return "mBTC"
return "mLBC"
case AmountMicroBTC:
return BTC"
return LBC"
case AmountSatoshi:
return "Satoshi"
default:
return "1e" + strconv.FormatInt(int64(u), 10) + " BTC"
return "1e" + strconv.FormatInt(int64(u), 10) + " LBC"
}
}
@ -72,7 +72,7 @@ func round(f float64) Amount {
// NewAmount is for specifically for converting BTC to Satoshi.
// For creating a new Amount with an int64 value which denotes a quantity of Satoshi,
// do a simple type conversion from type int64 to Amount.
// See GoDoc for example: http://godoc.org/github.com/btcsuite/btcutil#example-Amount
// See GoDoc for example: http://godoc.org/github.com/lbryio/lbcutil#example-Amount
func NewAmount(f float64) (Amount, error) {
// The amount is only considered invalid if it cannot be represented
// as an integer type. This may happen if f is NaN or +-Infinity.

View file

@ -2,13 +2,13 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil_test
package lbcutil_test
import (
"math"
"testing"
. "github.com/btcsuite/btcutil"
. "github.com/lbryio/lbcutil"
)
func TestAmountCreation(t *testing.T) {
@ -119,40 +119,40 @@ func TestAmountUnitConversions(t *testing.T) {
s string
}{
{
name: "MBTC",
name: "MLBC",
amount: MaxSatoshi,
unit: AmountMegaBTC,
converted: 21,
s: "21 MBTC",
s: "21 MLBC",
},
{
name: "kBTC",
name: "kLBC",
amount: 44433322211100,
unit: AmountKiloBTC,
converted: 444.33322211100,
s: "444.333222111 kBTC",
s: "444.333222111 kLBC",
},
{
name: "BTC",
name: "LBC",
amount: 44433322211100,
unit: AmountBTC,
converted: 444333.22211100,
s: "444333.222111 BTC",
s: "444333.222111 LBC",
},
{
name: "mBTC",
name: "mLBC",
amount: 44433322211100,
unit: AmountMilliBTC,
converted: 444333222.11100,
s: "444333222.111 mBTC",
s: "444333222.111 mLBC",
},
{
name: BTC",
name: LBC",
amount: 44433322211100,
unit: AmountMicroBTC,
converted: 444333222111.00,
s: "444333222111 μBTC",
s: "444333222111 μLBC",
},
{
@ -168,7 +168,7 @@ func TestAmountUnitConversions(t *testing.T) {
amount: 44433322211100,
unit: AmountUnit(-1),
converted: 4443332.2211100,
s: "4443332.22111 1e-1 BTC",
s: "4443332.22111 1e-1 LBC",
},
}

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
import (
"os"

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil_test
package lbcutil_test
import (
"os"
@ -12,7 +12,7 @@ import (
"testing"
"unicode"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcutil"
)
// TestAppDataDir tests the API for AppDataDir to ensure it gives expected
@ -122,7 +122,7 @@ func TestAppDataDir(t *testing.T) {
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
ret := btcutil.TstAppDataDir(test.goos, test.appName, test.roaming)
ret := lbcutil.TstAppDataDir(test.goos, test.appName, test.roaming)
if ret != test.want {
t.Errorf("appDataDir #%d (%s) does not match - "+
"expected got %s, want %s", i, test.goos, ret,

View file

@ -1,9 +1,7 @@
base58
==========
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcutil/base58)
Package base58 provides an API for encoding and decoding to and from the
modified base58 encoding. It also provides an API to do Base58Check encoding,
@ -11,24 +9,13 @@ as described [here](https://en.bitcoin.it/wiki/Base58Check_encoding).
A comprehensive suite of tests is provided to ensure proper functionality.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil/base58
```
## Examples
* [Decode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-Decode)
* [Decode Example](http://godoc.org/github.com/lbryio/lbcutil/base58#example-Decode)
Demonstrates how to decode modified base58 encoded data.
* [Encode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-Encode)
* [Encode Example](http://godoc.org/github.com/lbryio/lbcutil/base58#example-Encode)
Demonstrates how to encode data using the modified base58 encoding scheme.
* [CheckDecode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-CheckDecode)
* [CheckDecode Example](http://godoc.org/github.com/lbryio/lbcutil/base58#example-CheckDecode)
Demonstrates how to decode Base58Check encoded data.
* [CheckEncode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-CheckEncode)
Demonstrates how to encode data using the Base58Check encoding scheme.
## License
Package base58 is licensed under the [copyfree](http://copyfree.org) ISC
License.
* [CheckEncode Example](http://godoc.org/github.com/lbryio/lbcutil/base58#example-CheckEncode)
Demonstrates how to encode data using the Base58Check encoding scheme.

View file

@ -10,24 +10,63 @@ import (
//go:generate go run genalphabet.go
var bigRadix = big.NewInt(58)
var bigZero = big.NewInt(0)
var bigRadix = [...]*big.Int{
big.NewInt(0),
big.NewInt(58),
big.NewInt(58 * 58),
big.NewInt(58 * 58 * 58),
big.NewInt(58 * 58 * 58 * 58),
big.NewInt(58 * 58 * 58 * 58 * 58),
big.NewInt(58 * 58 * 58 * 58 * 58 * 58),
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58),
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58),
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58),
bigRadix10,
}
var bigRadix10 = big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58) // 58^10
// Decode decodes a modified base58 string to a byte slice.
func Decode(b string) []byte {
answer := big.NewInt(0)
j := big.NewInt(1)
scratch := new(big.Int)
for i := len(b) - 1; i >= 0; i-- {
tmp := b58[b[i]]
if tmp == 255 {
return []byte("")
// Calculating with big.Int is slow for each iteration.
// x += b58[b[i]] * j
// j *= 58
//
// Instead we can try to do as much calculations on int64.
// We can represent a 10 digit base58 number using an int64.
//
// Hence we'll try to convert 10, base58 digits at a time.
// The rough idea is to calculate `t`, such that:
//
// t := b58[b[i+9]] * 58^9 ... + b58[b[i+1]] * 58^1 + b58[b[i]] * 58^0
// x *= 58^10
// x += t
//
// Of course, in addition, we'll need to handle boundary condition when `b` is not multiple of 58^10.
// In that case we'll use the bigRadix[n] lookup for the appropriate power.
for t := b; len(t) > 0; {
n := len(t)
if n > 10 {
n = 10
}
scratch.SetInt64(int64(tmp))
scratch.Mul(j, scratch)
total := uint64(0)
for _, v := range t[:n] {
tmp := b58[v]
if tmp == 255 {
return []byte("")
}
total = total*58 + uint64(tmp)
}
answer.Mul(answer, bigRadix[n])
scratch.SetUint64(total)
answer.Add(answer, scratch)
j.Mul(j, bigRadix)
t = t[n:]
}
tmpval := answer.Bytes()
@ -50,11 +89,35 @@ func Encode(b []byte) string {
x := new(big.Int)
x.SetBytes(b)
answer := make([]byte, 0, len(b)*136/100)
for x.Cmp(bigZero) > 0 {
mod := new(big.Int)
x.DivMod(x, bigRadix, mod)
answer = append(answer, alphabet[mod.Int64()])
// maximum length of output is log58(2^(8*len(b))) == len(b) * 8 / log(58)
maxlen := int(float64(len(b))*1.365658237309761) + 1
answer := make([]byte, 0, maxlen)
mod := new(big.Int)
for x.Sign() > 0 {
// Calculating with big.Int is slow for each iteration.
// x, mod = x / 58, x % 58
//
// Instead we can try to do as much calculations on int64.
// x, mod = x / 58^10, x % 58^10
//
// Which will give us mod, which is 10 digit base58 number.
// We'll loop that 10 times to convert to the answer.
x.DivMod(x, bigRadix10, mod)
if x.Sign() == 0 {
// When x = 0, we need to ensure we don't add any extra zeros.
m := mod.Int64()
for m > 0 {
answer = append(answer, alphabet[m%58])
m /= 58
}
} else {
m := mod.Int64()
for i := 0; i < 10; i++ {
answer = append(answer, alphabet[m%58])
m /= 58
}
}
}
// leading zero bytes

View file

@ -9,7 +9,7 @@ import (
"encoding/hex"
"testing"
"github.com/btcsuite/btcutil/base58"
"github.com/lbryio/lbcutil/base58"
)
var stringTests = []struct {
@ -49,6 +49,7 @@ var hexTests = []struct {
in string
out string
}{
{"", ""},
{"61", "2g"},
{"626262", "a3gV"},
{"636363", "aPEr"},
@ -60,6 +61,8 @@ var hexTests = []struct {
{"ecac89cad93923c02321", "EJDM8drfXA6uyA"},
{"10c8511e", "Rt5zm"},
{"00000000000000000000", "1111111111"},
{"000111d38e5fc9071ffcd20b4a763cc9ae4f252bb4e48fd66a835e252ada93ff480d6dd43dc62a641155a5", "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"},
{"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "1cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY"},
}
func TestBase58(t *testing.T) {

View file

@ -8,28 +8,40 @@ import (
"bytes"
"testing"
"github.com/btcsuite/btcutil/base58"
"github.com/lbryio/lbcutil/base58"
)
func BenchmarkBase58Encode(b *testing.B) {
b.StopTimer()
data := bytes.Repeat([]byte{0xff}, 5000)
b.SetBytes(int64(len(data)))
b.StartTimer()
var (
raw5k = bytes.Repeat([]byte{0xff}, 5000)
raw100k = bytes.Repeat([]byte{0xff}, 100*1000)
encoded5k = base58.Encode(raw5k)
encoded100k = base58.Encode(raw100k)
)
func BenchmarkBase58Encode_5K(b *testing.B) {
b.SetBytes(int64(len(raw5k)))
for i := 0; i < b.N; i++ {
base58.Encode(data)
base58.Encode(raw5k)
}
}
func BenchmarkBase58Decode(b *testing.B) {
b.StopTimer()
data := bytes.Repeat([]byte{0xff}, 5000)
encoded := base58.Encode(data)
b.SetBytes(int64(len(encoded)))
b.StartTimer()
func BenchmarkBase58Encode_100K(b *testing.B) {
b.SetBytes(int64(len(raw100k)))
for i := 0; i < b.N; i++ {
base58.Decode(encoded)
base58.Encode(raw100k)
}
}
func BenchmarkBase58Decode_5K(b *testing.B) {
b.SetBytes(int64(len(encoded5k)))
for i := 0; i < b.N; i++ {
base58.Decode(encoded5k)
}
}
func BenchmarkBase58Decode_100K(b *testing.B) {
b.SetBytes(int64(len(encoded100k)))
for i := 0; i < b.N; i++ {
base58.Decode(encoded100k)
}
}

View file

@ -7,7 +7,7 @@ package base58_test
import (
"testing"
"github.com/btcsuite/btcutil/base58"
"github.com/lbryio/lbcutil/base58"
)
var checkEncodingStringTests = []struct {
@ -56,7 +56,7 @@ func TestBase58Check(t *testing.T) {
// bytes are missing).
testString := ""
for len := 0; len < 4; len++ {
// make a string of length `len`
testString = testString + "x"
_, _, err = base58.CheckDecode(testString)
if err != base58.ErrInvalidFormat {
t.Error("Checkdecode test failed, expected ErrInvalidFormat")

View file

@ -7,7 +7,7 @@ package base58_test
import (
"fmt"
"github.com/btcsuite/btcutil/base58"
"github.com/lbryio/lbcutil/base58"
)
// This example demonstrates how to decode modified base58 encoded data.

View file

@ -1,29 +1,16 @@
bech32
==========
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://godoc.org/github.com/btcsuite/btcutil/bech32?status.png)](http://godoc.org/github.com/btcsuite/btcutil/bech32)
Package bech32 provides a Go implementation of the bech32 format specified in
[BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki).
Test vectors from BIP 173 are added to ensure compatibility with the BIP.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil/bech32
```
## Examples
* [Bech32 decode Example](http://godoc.org/github.com/btcsuite/btcutil/bech32#example-Bech32Decode)
* [Bech32 decode Example](http://godoc.org/github.com/lbryio/lbcutil/bech32#example-Bech32Decode)
Demonstrates how to decode a bech32 encoded string.
* [Bech32 encode Example](http://godoc.org/github.com/btcsuite/btcutil/bech32#example-BechEncode)
* [Bech32 encode Example](http://godoc.org/github.com/lbryio/lbcutil/bech32#example-BechEncode)
Demonstrates how to encode data into a bech32 string.
## License
Package bech32 is licensed under the [copyfree](http://copyfree.org) ISC
License.

View file

@ -1,54 +1,197 @@
// Copyright (c) 2017 The btcsuite developers
// Copyright (c) 2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package bech32
import (
"fmt"
"strings"
)
// charset is the set of characters used in the data section of bech32 strings.
// Note that this is ordered, such that for a given charset[i], i is the binary
// value of the character.
const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
// gen encodes the generator polynomial for the bech32 BCH checksum.
var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
// Decode decodes a bech32 encoded string, returning the human-readable
// part and the data part excluding the checksum.
func Decode(bech string) (string, []byte, error) {
// The maximum allowed length for a bech32 string is 90. It must also
// be at least 8 characters, since it needs a non-empty HRP, a
// separator, and a 6 character checksum.
if len(bech) < 8 || len(bech) > 90 {
return "", nil, fmt.Errorf("invalid bech32 string length %d",
len(bech))
// toBytes converts each character in the string 'chars' to the value of the
// index of the correspoding character in 'charset'.
func toBytes(chars string) ([]byte, error) {
decoded := make([]byte, 0, len(chars))
for i := 0; i < len(chars); i++ {
index := strings.IndexByte(charset, chars[i])
if index < 0 {
return nil, ErrNonCharsetChar(chars[i])
}
decoded = append(decoded, byte(index))
}
// Only ASCII characters between 33 and 126 are allowed.
for i := 0; i < len(bech); i++ {
if bech[i] < 33 || bech[i] > 126 {
return "", nil, fmt.Errorf("invalid character in "+
"string: '%c'", bech[i])
return decoded, nil
}
// bech32Polymod calculates the BCH checksum for a given hrp, values and
// checksum data. Checksum is optional, and if nil a 0 checksum is assumed.
//
// Values and checksum (if provided) MUST be encoded as 5 bits per element (base
// 32), otherwise the results are undefined.
//
// For more details on the polymod calculation, please refer to BIP 173.
func bech32Polymod(hrp string, values, checksum []byte) int {
chk := 1
// Account for the high bits of the HRP in the checksum.
for i := 0; i < len(hrp); i++ {
b := chk >> 25
hiBits := int(hrp[i]) >> 5
chk = (chk&0x1ffffff)<<5 ^ hiBits
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
chk ^= gen[i]
}
}
}
// The characters must be either all lowercase or all uppercase.
lower := strings.ToLower(bech)
upper := strings.ToUpper(bech)
if bech != lower && bech != upper {
return "", nil, fmt.Errorf("string not all lowercase or all " +
"uppercase")
// Account for the separator (0) between high and low bits of the HRP.
// x^0 == x, so we eliminate the redundant xor used in the other rounds.
b := chk >> 25
chk = (chk & 0x1ffffff) << 5
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
chk ^= gen[i]
}
}
// We'll work with the lowercase string from now on.
bech = lower
// Account for the low bits of the HRP.
for i := 0; i < len(hrp); i++ {
b := chk >> 25
loBits := int(hrp[i]) & 31
chk = (chk&0x1ffffff)<<5 ^ loBits
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
chk ^= gen[i]
}
}
}
// Account for the values.
for _, v := range values {
b := chk >> 25
chk = (chk&0x1ffffff)<<5 ^ int(v)
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
chk ^= gen[i]
}
}
}
if checksum == nil {
// A nil checksum is used during encoding, so assume all bytes are zero.
// x^0 == x, so we eliminate the redundant xor used in the other rounds.
for v := 0; v < 6; v++ {
b := chk >> 25
chk = (chk & 0x1ffffff) << 5
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
chk ^= gen[i]
}
}
}
} else {
// Checksum is provided during decoding, so use it.
for _, v := range checksum {
b := chk >> 25
chk = (chk&0x1ffffff)<<5 ^ int(v)
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
chk ^= gen[i]
}
}
}
}
return chk
}
// writeBech32Checksum calculates the checksum data expected for a string that
// will have the given hrp and payload data and writes it to the provided string
// builder.
//
// The payload data MUST be encoded as a base 32 (5 bits per element) byte slice
// and the hrp MUST only use the allowed character set (ascii chars between 33
// and 126), otherwise the results are undefined.
//
// For more details on the checksum calculation, please refer to BIP 173.
func writeBech32Checksum(hrp string, data []byte, bldr *strings.Builder) {
polymod := bech32Polymod(hrp, data, nil) ^ 1
for i := 0; i < 6; i++ {
b := byte((polymod >> uint(5*(5-i))) & 31)
// This can't fail, given we explicitly cap the previous b byte by the
// first 31 bits.
c := charset[b]
bldr.WriteByte(c)
}
}
// bech32VerifyChecksum verifies whether the bech32 string specified by the
// provided hrp and payload data (encoded as 5 bits per element byte slice) has
// the correct checksum suffix.
//
// Data MUST have more than 6 elements, otherwise this function panics.
//
// For more details on the checksum verification, please refer to BIP 173.
func bech32VerifyChecksum(hrp string, data []byte) bool {
checksum := data[len(data)-6:]
values := data[:len(data)-6]
polymod := bech32Polymod(hrp, values, checksum)
return polymod == 1
}
// DecodeNoLimit decodes a bech32 encoded string, returning the human-readable
// part and the data part excluding the checksum. This function does NOT
// validate against the BIP-173 maximum length allowed for bech32 strings and
// is meant for use in custom applications (such as lightning network payment
// requests), NOT on-chain addresses.
//
// Note that the returned data is 5-bit (base32) encoded and the human-readable
// part will be lowercase.
func DecodeNoLimit(bech string) (string, []byte, error) {
// The minimum allowed size of a bech32 string is 8 characters, since it
// needs a non-empty HRP, a separator, and a 6 character checksum.
if len(bech) < 8 {
return "", nil, ErrInvalidLength(len(bech))
}
// Only ASCII characters between 33 and 126 are allowed.
var hasLower, hasUpper bool
for i := 0; i < len(bech); i++ {
if bech[i] < 33 || bech[i] > 126 {
return "", nil, ErrInvalidCharacter(bech[i])
}
// The characters must be either all lowercase or all uppercase. Testing
// directly with ascii codes is safe here, given the previous test.
hasLower = hasLower || (bech[i] >= 97 && bech[i] <= 122)
hasUpper = hasUpper || (bech[i] >= 65 && bech[i] <= 90)
if hasLower && hasUpper {
return "", nil, ErrMixedCase{}
}
}
// Bech32 standard uses only the lowercase for of strings for checksum
// calculation.
if hasUpper {
bech = strings.ToLower(bech)
}
// The string is invalid if the last '1' is non-existent, it is the
// first character of the string (no human-readable part) or one of the
// last 6 characters of the string (since checksum cannot contain '1'),
// or if the string is more than 90 characters in total.
// last 6 characters of the string (since checksum cannot contain '1').
one := strings.LastIndexByte(bech, '1')
if one < 1 || one+7 > len(bech) {
return "", nil, fmt.Errorf("invalid index of 1")
return "", nil, ErrInvalidSeparatorIndex(one)
}
// The human-readable part is everything before the last '1'.
@ -59,85 +202,96 @@ func Decode(bech string) (string, []byte, error) {
// 'charset'.
decoded, err := toBytes(data)
if err != nil {
return "", nil, fmt.Errorf("failed converting data to bytes: "+
"%v", err)
return "", nil, err
}
// Verify if the checksum (stored inside decoded[:]) is valid, given the
// previously decoded hrp.
if !bech32VerifyChecksum(hrp, decoded) {
moreInfo := ""
checksum := bech[len(bech)-6:]
expected, err := toChars(bech32Checksum(hrp,
decoded[:len(decoded)-6]))
if err == nil {
moreInfo = fmt.Sprintf("Expected %v, got %v.",
expected, checksum)
// Invalid checksum. Calculate what it should have been, so that the
// error contains this information.
// Extract the payload bytes and actual checksum in the string.
actual := bech[len(bech)-6:]
payload := decoded[:len(decoded)-6]
// Calculate the expected checksum, given the hrp and payload data.
var expectedBldr strings.Builder
expectedBldr.Grow(6)
writeBech32Checksum(hrp, payload, &expectedBldr)
expected := expectedBldr.String()
err = ErrInvalidChecksum{
Expected: expected,
Actual: actual,
}
return "", nil, fmt.Errorf("checksum failed. " + moreInfo)
return "", nil, err
}
// We exclude the last 6 bytes, which is the checksum.
return hrp, decoded[:len(decoded)-6], nil
}
// Encode encodes a byte slice into a bech32 string with the
// human-readable part hrb. Note that the bytes must each encode 5 bits
// (base32).
// Decode decodes a bech32 encoded string, returning the human-readable part and
// the data part excluding the checksum.
//
// Note that the returned data is 5-bit (base32) encoded and the human-readable
// part will be lowercase.
func Decode(bech string) (string, []byte, error) {
// The maximum allowed length for a bech32 string is 90.
if len(bech) > 90 {
return "", nil, ErrInvalidLength(len(bech))
}
return DecodeNoLimit(bech)
}
// Encode encodes a byte slice into a bech32 string with the given
// human-readable part (HRP). The HRP will be converted to lowercase if needed
// since mixed cased encodings are not permitted and lowercase is used for
// checksum purposes. Note that the bytes must each encode 5 bits (base32).
func Encode(hrp string, data []byte) (string, error) {
// Calculate the checksum of the data and append it at the end.
checksum := bech32Checksum(hrp, data)
combined := append(data, checksum...)
// The resulting bech32 string is the concatenation of the lowercase hrp,
// the separator 1, data and the 6-byte checksum.
hrp = strings.ToLower(hrp)
var bldr strings.Builder
bldr.Grow(len(hrp) + 1 + len(data) + 6)
bldr.WriteString(hrp)
bldr.WriteString("1")
// The resulting bech32 string is the concatenation of the hrp, the
// separator 1, data and checksum. Everything after the separator is
// represented using the specified charset.
dataChars, err := toChars(combined)
if err != nil {
return "", fmt.Errorf("unable to convert data bytes to chars: "+
"%v", err)
}
return hrp + "1" + dataChars, nil
}
// toBytes converts each character in the string 'chars' to the value of the
// index of the correspoding character in 'charset'.
func toBytes(chars string) ([]byte, error) {
decoded := make([]byte, 0, len(chars))
for i := 0; i < len(chars); i++ {
index := strings.IndexByte(charset, chars[i])
if index < 0 {
return nil, fmt.Errorf("invalid character not part of "+
"charset: %v", chars[i])
}
decoded = append(decoded, byte(index))
}
return decoded, nil
}
// toChars converts the byte slice 'data' to a string where each byte in 'data'
// encodes the index of a character in 'charset'.
func toChars(data []byte) (string, error) {
result := make([]byte, 0, len(data))
// Write the data part, using the bech32 charset.
for _, b := range data {
if int(b) >= len(charset) {
return "", fmt.Errorf("invalid data byte: %v", b)
return "", ErrInvalidDataByte(b)
}
result = append(result, charset[b])
bldr.WriteByte(charset[b])
}
return string(result), nil
// Calculate and write the checksum of the data.
writeBech32Checksum(hrp, data, &bldr)
return bldr.String(), nil
}
// ConvertBits converts a byte slice where each byte is encoding fromBits bits,
// to a byte slice where each byte is encoding toBits bits.
func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
return nil, fmt.Errorf("only bit groups between 1 and 8 allowed")
return nil, ErrInvalidBitGroups{}
}
// Determine the maximum size the resulting array can have after base
// conversion, so that we can size it a single time. This might be off
// by a byte depending on whether padding is used or not and if the input
// data is a multiple of both fromBits and toBits, but we ignore that and
// just size it to the maximum possible.
maxSize := len(data)*int(fromBits)/int(toBits) + 1
// The final bytes, each byte encoding toBits bits.
var regrouped []byte
regrouped := make([]byte, 0, maxSize)
// Keep track of the next byte we create and how many bits we have
// added to it out of the toBits goal.
// added to it out of the toBits goal.
nextByte := byte(0)
filledBits := uint8(0)
@ -170,7 +324,7 @@ func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error)
filledBits += toExtract
// If the nextByte is completely filled, we add it to
// our regrouped bytes and start on the next byte.
// our regrouped bytes and start on the next byte.
if filledBits == toBits {
regrouped = append(regrouped, nextByte)
filledBits = 0
@ -189,64 +343,36 @@ func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error)
// Any incomplete group must be <= 4 bits, and all zeroes.
if filledBits > 0 && (filledBits > 4 || nextByte != 0) {
return nil, fmt.Errorf("invalid incomplete group")
return nil, ErrInvalidIncompleteGroup{}
}
return regrouped, nil
}
// For more details on the checksum calculation, please refer to BIP 173.
func bech32Checksum(hrp string, data []byte) []byte {
// Convert the bytes to list of integers, as this is needed for the
// checksum calculation.
integers := make([]int, len(data))
for i, b := range data {
integers[i] = int(b)
// EncodeFromBase256 converts a base256-encoded byte slice into a base32-encoded
// byte slice and then encodes it into a bech32 string with the given
// human-readable part (HRP). The HRP will be converted to lowercase if needed
// since mixed cased encodings are not permitted and lowercase is used for
// checksum purposes.
func EncodeFromBase256(hrp string, data []byte) (string, error) {
converted, err := ConvertBits(data, 8, 5, true)
if err != nil {
return "", err
}
values := append(bech32HrpExpand(hrp), integers...)
values = append(values, []int{0, 0, 0, 0, 0, 0}...)
polymod := bech32Polymod(values) ^ 1
var res []byte
for i := 0; i < 6; i++ {
res = append(res, byte((polymod>>uint(5*(5-i)))&31))
}
return res
return Encode(hrp, converted)
}
// For more details on the polymod calculation, please refer to BIP 173.
func bech32Polymod(values []int) int {
chk := 1
for _, v := range values {
b := chk >> 25
chk = (chk&0x1ffffff)<<5 ^ v
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
chk ^= gen[i]
}
}
// DecodeToBase256 decodes a bech32-encoded string into its associated
// human-readable part (HRP) and base32-encoded data, converts that data to a
// base256-encoded byte slice and returns it along with the lowercase HRP.
func DecodeToBase256(bech string) (string, []byte, error) {
hrp, data, err := Decode(bech)
if err != nil {
return "", nil, err
}
return chk
}
// For more details on HRP expansion, please refer to BIP 173.
func bech32HrpExpand(hrp string) []int {
v := make([]int, 0, len(hrp)*2+1)
for i := 0; i < len(hrp); i++ {
v = append(v, int(hrp[i]>>5))
}
v = append(v, 0)
for i := 0; i < len(hrp); i++ {
v = append(v, int(hrp[i]&31))
}
return v
}
// For more details on the checksum verification, please refer to BIP 173.
func bech32VerifyChecksum(hrp string, data []byte) bool {
integers := make([]int, len(data))
for i, b := range data {
integers[i] = int(b)
}
concat := append(bech32HrpExpand(hrp), integers...)
return bech32Polymod(concat) == 1
converted, err := ConvertBits(data, 5, 8, false)
if err != nil {
return "", nil, err
}
return hrp, converted, nil
}

View file

@ -1,54 +1,72 @@
// Copyright (c) 2017 The btcsuite developers
// Copyright (c) 2017-2020 The btcsuite developers
// Copyright (c) 2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package bech32_test
package bech32
import (
"bytes"
"encoding/hex"
"fmt"
"strings"
"testing"
"github.com/btcsuite/btcutil/bech32"
)
// TestBech32 tests whether decoding and re-encoding the valid BIP-173 test
// vectors works and if decoding invalid test vectors fails for the correct
// reason.
func TestBech32(t *testing.T) {
tests := []struct {
str string
valid bool
str string
expectedError error
}{
{"A12UEL5L", true},
{"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", true},
{"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", true},
{"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", true},
{"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", true},
{"split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", false}, // invalid checksum
{"s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", false}, // invalid character (space) in hrp
{"spl" + string(127) + "t1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", false}, // invalid character (DEL) in hrp
{"split1cheo2y9e2w", false}, // invalid character (o) in data part
{"split1a2y9w", false}, // too short data part
{"1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", false}, // empty hrp
{"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", false}, // too long
{"A12UEL5L", nil},
{"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", nil},
{"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", nil},
{"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", nil},
{"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", nil},
{"split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", ErrInvalidChecksum{"2y9e3w", "2y9e2w"}}, // invalid checksum
{"s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", ErrInvalidCharacter(' ')}, // invalid character (space) in hrp
{"spl\x7Ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", ErrInvalidCharacter(127)}, // invalid character (DEL) in hrp
{"split1cheo2y9e2w", ErrNonCharsetChar('o')}, // invalid character (o) in data part
{"split1a2y9w", ErrInvalidSeparatorIndex(5)}, // too short data part
{"1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", ErrInvalidSeparatorIndex(0)}, // empty hrp
{"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", ErrInvalidLength(91)}, // too long
// Additional test vectors used in bitcoin core
{" 1nwldj5", ErrInvalidCharacter(' ')},
{"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)},
{"\x801eym55h", ErrInvalidCharacter(0x80)},
{"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", ErrInvalidLength(91)},
{"pzry9x0s0muk", ErrInvalidSeparatorIndex(-1)},
{"1pzry9x0s0muk", ErrInvalidSeparatorIndex(0)},
{"x1b4n0q5v", ErrNonCharsetChar(98)},
{"li1dgmt3", ErrInvalidSeparatorIndex(2)},
{"de1lg7wt\xff", ErrInvalidCharacter(0xff)},
{"A1G7SGD8", ErrInvalidChecksum{"2uel5l", "g7sgd8"}},
{"10a06t8", ErrInvalidLength(7)},
{"1qzzfhee", ErrInvalidSeparatorIndex(0)},
{"a12UEL5L", ErrMixedCase{}},
{"A12uEL5L", ErrMixedCase{}},
}
for _, test := range tests {
for i, test := range tests {
str := test.str
hrp, decoded, err := bech32.Decode(str)
if !test.valid {
// Invalid string decoding should result in error.
if err == nil {
t.Error("expected decoding to fail for "+
"invalid string %v", test.str)
}
hrp, decoded, err := Decode(str)
if test.expectedError != err {
t.Errorf("%d: expected decoding error %v "+
"instead got %v", i, test.expectedError, err)
continue
}
// Valid string decoding should result in no error.
if err != nil {
t.Errorf("expected string to be valid bech32: %v", err)
// End test case here if a decoding error was expected.
continue
}
// Check that it encodes to the same string
encoded, err := bech32.Encode(hrp, decoded)
encoded, err := Encode(hrp, decoded)
if err != nil {
t.Errorf("encoding failed: %v", err)
}
@ -61,9 +79,491 @@ func TestBech32(t *testing.T) {
// Flip a bit in the string an make sure it is caught.
pos := strings.LastIndexAny(str, "1")
flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
_, _, err = bech32.Decode(flipped)
_, _, err = Decode(flipped)
if err == nil {
t.Error("expected decoding to fail")
}
}
}
// TestMixedCaseEncode ensures mixed case HRPs are converted to lowercase as
// expected when encoding and that decoding the produced encoding when converted
// to all uppercase produces the lowercase HRP and original data.
func TestMixedCaseEncode(t *testing.T) {
tests := []struct {
name string
hrp string
data string
encoded string
}{{
name: "all uppercase HRP with no data",
hrp: "A",
data: "",
encoded: "a12uel5l",
}, {
name: "all uppercase HRP with data",
hrp: "UPPERCASE",
data: "787878",
encoded: "uppercase10pu8sss7kmp",
}, {
name: "mixed case HRP even offsets uppercase",
hrp: "AbCdEf",
data: "00443214c74254b635cf84653a56d7c675be77df",
encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
}, {
name: "mixed case HRP odd offsets uppercase ",
hrp: "aBcDeF",
data: "00443214c74254b635cf84653a56d7c675be77df",
encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
}, {
name: "all lowercase HRP",
hrp: "abcdef",
data: "00443214c74254b635cf84653a56d7c675be77df",
encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
}}
for _, test := range tests {
// Convert the text hex to bytes, convert those bytes from base256 to
// base32, then ensure the encoded result with the HRP provided in the
// test data is as expected.
data, err := hex.DecodeString(test.data)
if err != nil {
t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err)
continue
}
convertedData, err := ConvertBits(data, 8, 5, true)
if err != nil {
t.Errorf("%q: unexpected convert bits error: %v", test.name,
err)
continue
}
gotEncoded, err := Encode(test.hrp, convertedData)
if err != nil {
t.Errorf("%q: unexpected encode error: %v", test.name, err)
continue
}
if gotEncoded != test.encoded {
t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
gotEncoded, test.encoded)
continue
}
// Ensure the decoding the expected lowercase encoding converted to all
// uppercase produces the lowercase HRP and original data.
gotHRP, gotData, err := Decode(strings.ToUpper(test.encoded))
if err != nil {
t.Errorf("%q: unexpected decode error: %v", test.name, err)
continue
}
wantHRP := strings.ToLower(test.hrp)
if gotHRP != wantHRP {
t.Errorf("%q: mismatched decoded HRP -- got %q, want %q", test.name,
gotHRP, wantHRP)
continue
}
convertedGotData, err := ConvertBits(gotData, 5, 8, false)
if err != nil {
t.Errorf("%q: unexpected convert bits error: %v", test.name,
err)
continue
}
if !bytes.Equal(convertedGotData, data) {
t.Errorf("%q: mismatched data -- got %x, want %x", test.name,
convertedGotData, data)
continue
}
}
}
// TestCanDecodeUnlimtedBech32 tests whether decoding a large bech32 string works
// when using the DecodeNoLimit version
func TestCanDecodeUnlimtedBech32(t *testing.T) {
input := "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5kx0yd"
// Sanity check that an input of this length errors on regular Decode()
_, _, err := Decode(input)
if err == nil {
t.Fatalf("Test vector not appropriate")
}
// Try and decode it.
hrp, data, err := DecodeNoLimit(input)
if err != nil {
t.Fatalf("Expected decoding of large string to work. Got error: %v", err)
}
// Verify data for correctness.
if hrp != "1" {
t.Fatalf("Unexpected hrp: %v", hrp)
}
decodedHex := fmt.Sprintf("%x", data)
expected := "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000"
if decodedHex != expected {
t.Fatalf("Unexpected decoded data: %s", decodedHex)
}
}
// TestBech32Base256 ensures decoding and encoding various bech32, HRPs, and
// data produces the expected results when using EncodeFromBase256 and
// DecodeToBase256. It includes tests for proper handling of case
// manipulations.
func TestBech32Base256(t *testing.T) {
tests := []struct {
name string // test name
encoded string // bech32 string to decode
hrp string // expected human-readable part
data string // expected hex-encoded data
err error // expected error
}{{
name: "all uppercase, no data",
encoded: "A12UEL5L",
hrp: "a",
data: "",
}, {
name: "long hrp with separator and excluded chars, no data",
encoded: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
hrp: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio",
data: "",
}, {
name: "6 char hrp with data with leading zero",
encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
hrp: "abcdef",
data: "00443214c74254b635cf84653a56d7c675be77df",
}, {
name: "hrp same as separator and max length encoded string",
encoded: "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
hrp: "1",
data: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
}, {
name: "5 char hrp with data chosen to produce human-readable data part",
encoded: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
hrp: "split",
data: "c5f38b70305f519bf66d85fb6cf03058f3dde463ecd7918f2dc743918f2d",
}, {
name: "same as previous but with checksum invalidated",
encoded: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w",
err: ErrInvalidChecksum{"2y9e3w", "2y9e2w"},
}, {
name: "hrp with invalid character (space)",
encoded: "s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p",
err: ErrInvalidCharacter(' '),
}, {
name: "hrp with invalid character (DEL)",
encoded: "spl\x7ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
err: ErrInvalidCharacter(127),
}, {
name: "data part with invalid character (o)",
encoded: "split1cheo2y9e2w",
err: ErrNonCharsetChar('o'),
}, {
name: "data part too short",
encoded: "split1a2y9w",
err: ErrInvalidSeparatorIndex(5),
}, {
name: "empty hrp",
encoded: "1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
err: ErrInvalidSeparatorIndex(0),
}, {
name: "no separator",
encoded: "pzry9x0s0muk",
err: ErrInvalidSeparatorIndex(-1),
}, {
name: "too long by one char",
encoded: "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
err: ErrInvalidLength(91),
}, {
name: "invalid due to mixed case in hrp",
encoded: "aBcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
err: ErrMixedCase{},
}, {
name: "invalid due to mixed case in data part",
encoded: "abcdef1Qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
err: ErrMixedCase{},
}}
for _, test := range tests {
// Ensure the decode either produces an error or not as expected.
str := test.encoded
gotHRP, gotData, err := DecodeToBase256(str)
if test.err != err {
t.Errorf("%q: unexpected decode error -- got %v, want %v",
test.name, err, test.err)
continue
}
if err != nil {
// End test case here if a decoding error was expected.
continue
}
// Ensure the expected HRP and original data are as expected.
if gotHRP != test.hrp {
t.Errorf("%q: mismatched decoded HRP -- got %q, want %q", test.name,
gotHRP, test.hrp)
continue
}
data, err := hex.DecodeString(test.data)
if err != nil {
t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err)
continue
}
if !bytes.Equal(gotData, data) {
t.Errorf("%q: mismatched data -- got %x, want %x", test.name,
gotData, data)
continue
}
// Encode the same data with the HRP converted to all uppercase and
// ensure the result is the lowercase version of the original encoded
// bech32 string.
gotEncoded, err := EncodeFromBase256(strings.ToUpper(test.hrp), data)
if err != nil {
t.Errorf("%q: unexpected uppercase HRP encode error: %v", test.name,
err)
}
wantEncoded := strings.ToLower(str)
if gotEncoded != wantEncoded {
t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
gotEncoded, wantEncoded)
}
// Encode the same data with the HRP converted to all lowercase and
// ensure the result is the lowercase version of the original encoded
// bech32 string.
gotEncoded, err = EncodeFromBase256(strings.ToLower(test.hrp), data)
if err != nil {
t.Errorf("%q: unexpected lowercase HRP encode error: %v", test.name,
err)
}
if gotEncoded != wantEncoded {
t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
gotEncoded, wantEncoded)
}
// Encode the same data with the HRP converted to mixed upper and
// lowercase and ensure the result is the lowercase version of the
// original encoded bech32 string.
var mixedHRPBuilder strings.Builder
for i, r := range test.hrp {
if i%2 == 0 {
mixedHRPBuilder.WriteString(strings.ToUpper(string(r)))
continue
}
mixedHRPBuilder.WriteRune(r)
}
gotEncoded, err = EncodeFromBase256(mixedHRPBuilder.String(), data)
if err != nil {
t.Errorf("%q: unexpected lowercase HRP encode error: %v", test.name,
err)
}
if gotEncoded != wantEncoded {
t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
gotEncoded, wantEncoded)
}
// Ensure a bit flip in the string is caught.
pos := strings.LastIndexAny(test.encoded, "1")
flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
_, _, err = DecodeToBase256(flipped)
if err == nil {
t.Error("expected decoding to fail")
}
}
}
// BenchmarkEncodeDecodeCycle performs a benchmark for a full encode/decode
// cycle of a bech32 string. It also reports the allocation count, which we
// expect to be 2 for a fully optimized cycle.
func BenchmarkEncodeDecodeCycle(b *testing.B) {
// Use a fixed, 49-byte raw data for testing.
inputData, err := hex.DecodeString("cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1")
if err != nil {
b.Fatalf("failed to initialize input data: %v", err)
}
// Convert this into a 79-byte, base 32 byte slice.
base32Input, err := ConvertBits(inputData, 8, 5, true)
if err != nil {
b.Fatalf("failed to convert input to 32 bits-per-element: %v", err)
}
// Use a fixed hrp for the tests. This should generate an encoded bech32
// string of size 90 (the maximum allowed by BIP-173).
hrp := "bc"
// Begin the benchmark. Given that we test one roundtrip per iteration
// (that is, one Encode() and one Decode() operation), we expect at most
// 2 allocations per reported test op.
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
str, err := Encode(hrp, base32Input)
if err != nil {
b.Fatalf("failed to encode input: %v", err)
}
_, _, err = Decode(str)
if err != nil {
b.Fatalf("failed to decode string: %v", err)
}
}
}
// TestConvertBits tests whether base conversion works using TestConvertBits().
func TestConvertBits(t *testing.T) {
tests := []struct {
input string
output string
fromBits uint8
toBits uint8
pad bool
}{
// Trivial empty conversions.
{"", "", 8, 5, false},
{"", "", 8, 5, true},
{"", "", 5, 8, false},
{"", "", 5, 8, true},
// Conversions of 0 value with/without padding.
{"00", "00", 8, 5, false},
{"00", "0000", 8, 5, true},
{"0000", "00", 5, 8, false},
{"0000", "0000", 5, 8, true},
// Testing when conversion ends exactly at the byte edge. This makes
// both padded and unpadded versions the same.
{"0000000000", "0000000000000000", 8, 5, false},
{"0000000000", "0000000000000000", 8, 5, true},
{"0000000000000000", "0000000000", 5, 8, false},
{"0000000000000000", "0000000000", 5, 8, true},
// Conversions of full byte sequences.
{"ffffff", "1f1f1f1f1e", 8, 5, true},
{"1f1f1f1f1e", "ffffff", 5, 8, false},
{"1f1f1f1f1e", "ffffff00", 5, 8, true},
// Sample random conversions.
{"c9ca", "190705", 8, 5, false},
{"c9ca", "19070500", 8, 5, true},
{"19070500", "c9ca", 5, 8, false},
{"19070500", "c9ca00", 5, 8, true},
// Test cases tested on TestConvertBitsFailures with their corresponding
// fixes.
{"ff", "1f1c", 8, 5, true},
{"1f1c10", "ff20", 5, 8, true},
// Large conversions.
{
"cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1",
"190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408",
8, 5, true,
},
{
"190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408",
"cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed100",
5, 8, true,
},
}
for i, tc := range tests {
input, err := hex.DecodeString(tc.input)
if err != nil {
t.Fatalf("invalid test input data: %v", err)
}
expected, err := hex.DecodeString(tc.output)
if err != nil {
t.Fatalf("invalid test output data: %v", err)
}
actual, err := ConvertBits(input, tc.fromBits, tc.toBits, tc.pad)
if err != nil {
t.Fatalf("test case %d failed: %v", i, err)
}
if !bytes.Equal(actual, expected) {
t.Fatalf("test case %d has wrong output; expected=%x actual=%x",
i, expected, actual)
}
}
}
// TestConvertBitsFailures tests for the expected conversion failures of
// ConvertBits().
func TestConvertBitsFailures(t *testing.T) {
tests := []struct {
input string
fromBits uint8
toBits uint8
pad bool
err error
}{
// Not enough output bytes when not using padding.
{"ff", 8, 5, false, ErrInvalidIncompleteGroup{}},
{"1f1c10", 5, 8, false, ErrInvalidIncompleteGroup{}},
// Unsupported bit conversions.
{"", 0, 5, false, ErrInvalidBitGroups{}},
{"", 10, 5, false, ErrInvalidBitGroups{}},
{"", 5, 0, false, ErrInvalidBitGroups{}},
{"", 5, 10, false, ErrInvalidBitGroups{}},
}
for i, tc := range tests {
input, err := hex.DecodeString(tc.input)
if err != nil {
t.Fatalf("invalid test input data: %v", err)
}
_, err = ConvertBits(input, tc.fromBits, tc.toBits, tc.pad)
if err != tc.err {
t.Fatalf("test case %d failure: expected '%v' got '%v'", i,
tc.err, err)
}
}
}
// BenchmarkConvertBitsDown benchmarks the speed and memory allocation behavior
// of ConvertBits when converting from a higher base into a lower base (e.g. 8
// => 5).
//
// Only a single allocation is expected, which is used for the output array.
func BenchmarkConvertBitsDown(b *testing.B) {
// Use a fixed, 49-byte raw data for testing.
inputData, err := hex.DecodeString("cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1")
if err != nil {
b.Fatalf("failed to initialize input data: %v", err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := ConvertBits(inputData, 8, 5, true)
if err != nil {
b.Fatalf("error converting bits: %v", err)
}
}
}
// BenchmarkConvertBitsDown benchmarks the speed and memory allocation behavior
// of ConvertBits when converting from a lower base into a higher base (e.g. 5
// => 8).
//
// Only a single allocation is expected, which is used for the output array.
func BenchmarkConvertBitsUp(b *testing.B) {
// Use a fixed, 79-byte raw data for testing.
inputData, err := hex.DecodeString("190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408")
if err != nil {
b.Fatalf("failed to initialize input data: %v", err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := ConvertBits(inputData, 8, 5, true)
if err != nil {
b.Fatalf("error converting bits: %v", err)
}
}
}

85
bech32/error.go Normal file
View file

@ -0,0 +1,85 @@
// Copyright (c) 2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package bech32
import (
"fmt"
)
// ErrMixedCase is returned when the bech32 string has both lower and uppercase
// characters.
type ErrMixedCase struct{}
func (e ErrMixedCase) Error() string {
return "string not all lowercase or all uppercase"
}
// ErrInvalidBitGroups is returned when conversion is attempted between byte
// slices using bit-per-element of unsupported value.
type ErrInvalidBitGroups struct{}
func (e ErrInvalidBitGroups) Error() string {
return "only bit groups between 1 and 8 allowed"
}
// ErrInvalidIncompleteGroup is returned when then byte slice used as input has
// data of wrong length.
type ErrInvalidIncompleteGroup struct{}
func (e ErrInvalidIncompleteGroup) Error() string {
return "invalid incomplete group"
}
// ErrInvalidLength is returned when the bech32 string has an invalid length
// given the BIP-173 defined restrictions.
type ErrInvalidLength int
func (e ErrInvalidLength) Error() string {
return fmt.Sprintf("invalid bech32 string length %d", int(e))
}
// ErrInvalidCharacter is returned when the bech32 string has a character
// outside the range of the supported charset.
type ErrInvalidCharacter rune
func (e ErrInvalidCharacter) Error() string {
return fmt.Sprintf("invalid character in string: '%c'", rune(e))
}
// ErrInvalidSeparatorIndex is returned when the separator character '1' is
// in an invalid position in the bech32 string.
type ErrInvalidSeparatorIndex int
func (e ErrInvalidSeparatorIndex) Error() string {
return fmt.Sprintf("invalid separator index %d", int(e))
}
// ErrNonCharsetChar is returned when a character outside of the specific
// bech32 charset is used in the string.
type ErrNonCharsetChar rune
func (e ErrNonCharsetChar) Error() string {
return fmt.Sprintf("invalid character not part of charset: %v", int(e))
}
// ErrInvalidChecksum is returned when the extracted checksum of the string
// is different than what was expected.
type ErrInvalidChecksum struct {
Expected string
Actual string
}
func (e ErrInvalidChecksum) Error() string {
return fmt.Sprintf("invalid checksum (expected %v got %v)",
e.Expected, e.Actual)
}
// ErrInvalidDataByte is returned when a byte outside the range required for
// conversion into a string was found.
type ErrInvalidDataByte byte
func (e ErrInvalidDataByte) Error() string {
return fmt.Sprintf("invalid data byte: %v", byte(e))
}

View file

@ -8,7 +8,7 @@ import (
"encoding/hex"
"fmt"
"github.com/btcsuite/btcutil/bech32"
"github.com/lbryio/lbcutil/bech32"
)
// This example demonstrates how to decode a bech32 encoded string.
@ -45,5 +45,5 @@ func ExampleEncode() {
fmt.Println("Encoded Data:", encoded)
// Output:
// Encoded Data: customHrp!11111q123jhxapqv3shgcgumastr
// Encoded Data: customhrp!11111q123jhxapqv3shgcgkxpuhe
}

View file

@ -2,15 +2,15 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
import (
"bytes"
"fmt"
"io"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
)
// OutOfRangeError describes an error due to accessing an element that is out
@ -105,7 +105,7 @@ func (b *Block) Hash() *chainhash.Hash {
return &hash
}
// Tx returns a wrapped transaction (btcutil.Tx) for the transaction at the
// Tx returns a wrapped transaction (lbcutil.Tx) for the transaction at the
// specified index in the Block. The supplied index is 0 based. That is to
// say, the first transaction in the block is txNum 0. This is nearly
// equivalent to accessing the raw transaction (wire.MsgTx) from the
@ -114,7 +114,7 @@ func (b *Block) Hash() *chainhash.Hash {
func (b *Block) Tx(txNum int) (*Tx, error) {
// Ensure the requested transaction is in range.
numTx := uint64(len(b.msgBlock.Transactions))
if txNum < 0 || uint64(txNum) > numTx {
if txNum < 0 || uint64(txNum) >= numTx {
str := fmt.Sprintf("transaction index %d is out of range - max %d",
txNum, numTx-1)
return nil, OutOfRangeError(str)
@ -137,10 +137,10 @@ func (b *Block) Tx(txNum int) (*Tx, error) {
return newTx, nil
}
// Transactions returns a slice of wrapped transactions (btcutil.Tx) for all
// Transactions returns a slice of wrapped transactions (lbcutil.Tx) for all
// transactions in the Block. This is nearly equivalent to accessing the raw
// transactions (wire.MsgTx) in the underlying wire.MsgBlock, however it
// instead provides easy access to wrapped versions (btcutil.Tx) of them.
// instead provides easy access to wrapped versions (lbcutil.Tx) of them.
func (b *Block) Transactions() []*Tx {
// Return transactions if they have ALL already been generated. This
// flag is necessary because the wrapped transactions are lazily

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil_test
package lbcutil_test
import (
"bytes"
@ -11,15 +11,15 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
"github.com/davecgh/go-spew/spew"
)
// TestBlock tests the API for Block.
func TestBlock(t *testing.T) {
b := btcutil.NewBlock(&Block100000)
b := lbcutil.NewBlock(&Block100000)
// Ensure we get the same data back out.
if msgBlock := b.MsgBlock(); !reflect.DeepEqual(msgBlock, &Block100000) {
@ -60,7 +60,7 @@ func TestBlock(t *testing.T) {
}
// Create a new block to nuke all cached data.
b = btcutil.NewBlock(&Block100000)
b = lbcutil.NewBlock(&Block100000)
// Request hash for all transactions one at a time via Tx.
for i, txHash := range wantTxHashes {
@ -88,7 +88,7 @@ func TestBlock(t *testing.T) {
}
// Create a new block to nuke all cached data.
b = btcutil.NewBlock(&Block100000)
b = lbcutil.NewBlock(&Block100000)
// Request slice of all transactions multiple times to test generation
// and caching.
@ -145,10 +145,10 @@ func TestBlock(t *testing.T) {
// Transaction offsets and length for the transaction in Block100000.
wantTxLocs := []wire.TxLoc{
{TxStart: 81, TxLen: 135},
{TxStart: 216, TxLen: 259},
{TxStart: 475, TxLen: 257},
{TxStart: 732, TxLen: 225},
{TxStart: 81, TxLen: 144},
{TxStart: 225, TxLen: 259},
{TxStart: 484, TxLen: 257},
{TxStart: 741, TxLen: 225},
}
// Ensure the transaction location information is accurate.
@ -175,7 +175,7 @@ func TestNewBlockFromBytes(t *testing.T) {
block100000Bytes := block100000Buf.Bytes()
// Create a new block from the serialized bytes.
b, err := btcutil.NewBlockFromBytes(block100000Bytes)
b, err := lbcutil.NewBlockFromBytes(block100000Bytes)
if err != nil {
t.Errorf("NewBlockFromBytes: %v", err)
return
@ -212,7 +212,7 @@ func TestNewBlockFromBlockAndBytes(t *testing.T) {
block100000Bytes := block100000Buf.Bytes()
// Create a new block from the serialized bytes.
b := btcutil.NewBlockFromBlockAndBytes(&Block100000, block100000Bytes)
b := lbcutil.NewBlockFromBlockAndBytes(&Block100000, block100000Bytes)
// Ensure we get the same data back out.
serializedBytes, err := b.Bytes()
@ -235,7 +235,7 @@ func TestNewBlockFromBlockAndBytes(t *testing.T) {
func TestBlockErrors(t *testing.T) {
// Ensure out of range errors are as expected.
wantErr := "transaction index -1 is out of range - max 3"
testErr := btcutil.OutOfRangeError(wantErr)
testErr := lbcutil.OutOfRangeError(wantErr)
if testErr.Error() != wantErr {
t.Errorf("OutOfRangeError: wrong error - got %v, want %v",
testErr.Error(), wantErr)
@ -250,7 +250,7 @@ func TestBlockErrors(t *testing.T) {
block100000Bytes := block100000Buf.Bytes()
// Create a new block from the serialized bytes.
b, err := btcutil.NewBlockFromBytes(block100000Bytes)
b, err := lbcutil.NewBlockFromBytes(block100000Bytes)
if err != nil {
t.Errorf("NewBlockFromBytes: %v", err)
return
@ -258,7 +258,7 @@ func TestBlockErrors(t *testing.T) {
// Truncate the block byte buffer to force errors.
shortBytes := block100000Bytes[:80]
_, err = btcutil.NewBlockFromBytes(shortBytes)
_, err = lbcutil.NewBlockFromBytes(shortBytes)
if err != io.EOF {
t.Errorf("NewBlockFromBytes: did not get expected error - "+
"got %v, want %v", err, io.EOF)
@ -266,26 +266,26 @@ func TestBlockErrors(t *testing.T) {
// Ensure TxHash returns expected error on invalid indices.
_, err = b.TxHash(-1)
if _, ok := err.(btcutil.OutOfRangeError); !ok {
if _, ok := err.(lbcutil.OutOfRangeError); !ok {
t.Errorf("TxHash: wrong error - got: %v <%T>, "+
"want: <%T>", err, err, btcutil.OutOfRangeError(""))
"want: <%T>", err, err, lbcutil.OutOfRangeError(""))
}
_, err = b.TxHash(len(Block100000.Transactions) + 1)
if _, ok := err.(btcutil.OutOfRangeError); !ok {
_, err = b.TxHash(len(Block100000.Transactions))
if _, ok := err.(lbcutil.OutOfRangeError); !ok {
t.Errorf("TxHash: wrong error - got: %v <%T>, "+
"want: <%T>", err, err, btcutil.OutOfRangeError(""))
"want: <%T>", err, err, lbcutil.OutOfRangeError(""))
}
// Ensure Tx returns expected error on invalid indices.
_, err = b.Tx(-1)
if _, ok := err.(btcutil.OutOfRangeError); !ok {
if _, ok := err.(lbcutil.OutOfRangeError); !ok {
t.Errorf("Tx: wrong error - got: %v <%T>, "+
"want: <%T>", err, err, btcutil.OutOfRangeError(""))
"want: <%T>", err, err, lbcutil.OutOfRangeError(""))
}
_, err = b.Tx(len(Block100000.Transactions) + 1)
if _, ok := err.(btcutil.OutOfRangeError); !ok {
_, err = b.Tx(len(Block100000.Transactions))
if _, ok := err.(lbcutil.OutOfRangeError); !ok {
t.Errorf("Tx: wrong error - got: %v <%T>, "+
"want: <%T>", err, err, btcutil.OutOfRangeError(""))
"want: <%T>", err, err, lbcutil.OutOfRangeError(""))
}
// Ensure TxLoc returns expected error with short byte buffer.
@ -333,6 +333,10 @@ var Block100000 = wire.MsgBlock{
0x04, 0x4c, 0x86, 0x04, 0x1b, 0x02, 0x06, 0x02,
},
Sequence: 0xffffffff,
Witness: [][]byte{
{0x04, 0x31},
{0x01, 0x43},
},
},
},
TxOut: []*wire.TxOut{

View file

@ -1,9 +1,7 @@
bloom
=====
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcutil/bloom)
Package bloom provides an API for dealing with bitcoin-specific bloom filters.
@ -12,19 +10,8 @@ A comprehensive suite of tests is provided to ensure proper functionality. See
running a POSIX OS, you can run the `cov_report.sh` script for a real-time
report.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil/bloom
```
## Examples
* [NewFilter Example](http://godoc.org/github.com/btcsuite/btcutil/bloom#example-NewFilter)
* [NewFilter Example](http://godoc.org/github.com/lbryio/lbcutil/bloom#example-NewFilter)
Demonstrates how to create a new bloom filter, add a transaction hash to it,
and check if the filter matches the transaction.
## License
Package bloom is licensed under the [copyfree](http://copyfree.org) ISC
License.
and check if the filter matches the transaction.

View file

@ -9,9 +9,9 @@ import (
"math/rand"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil/bloom"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil/bloom"
)
// This example demonstrates how to create a new bloom filter, add a transaction

View file

@ -9,10 +9,10 @@ import (
"math"
"sync"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
)
// ln2Squared is simply the square of the natural log of 2.
@ -113,7 +113,7 @@ func (bf *Filter) Unload() {
}
// hash returns the bit offset in the bloom filter which corresponds to the
// passed data for the given indepedent hash function number.
// passed data for the given independent hash function number.
func (bf *Filter) hash(hashNum uint32, data []byte) uint32 {
// bitcoind: 0xfba4c795 chosen as it guarantees a reasonable bit
// difference between hashNum values.
@ -270,7 +270,7 @@ func (bf *Filter) maybeAddOutpoint(pkScript []byte, outHash *chainhash.Hash, out
// update flags set via the loaded filter if needed.
//
// This function MUST be called with the filter lock held.
func (bf *Filter) matchTxAndUpdate(tx *btcutil.Tx) bool {
func (bf *Filter) matchTxAndUpdate(tx *lbcutil.Tx) bool {
// Check if the filter matches the hash of the transaction.
// This is useful for finding transactions when they appear in a block.
matched := bf.matches(tx.Hash()[:])
@ -309,7 +309,7 @@ func (bf *Filter) matchTxAndUpdate(tx *btcutil.Tx) bool {
// public key scripts of its outputs matched.
// Check if the filter matches any outpoints this transaction spends or
// any any data elements in the signature scripts of any of the inputs.
// any data elements in the signature scripts of any of the inputs.
for _, txin := range tx.MsgTx().TxIn {
if bf.matchesOutPoint(&txin.PreviousOutPoint) {
return true
@ -335,7 +335,7 @@ func (bf *Filter) matchTxAndUpdate(tx *btcutil.Tx) bool {
// update flags set via the loaded filter if needed.
//
// This function is safe for concurrent access.
func (bf *Filter) MatchTxAndUpdate(tx *btcutil.Tx) bool {
func (bf *Filter) MatchTxAndUpdate(tx *lbcutil.Tx) bool {
bf.mtx.Lock()
match := bf.matchTxAndUpdate(tx)
bf.mtx.Unlock()

View file

@ -9,10 +9,10 @@ import (
"encoding/hex"
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/bloom"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
"github.com/lbryio/lbcutil/bloom"
)
// TestFilterLarge ensures a maximum sized filter can be created.
@ -214,7 +214,7 @@ func TestFilterInsertWithTweak(t *testing.T) {
func TestFilterInsertKey(t *testing.T) {
secret := "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"
wif, err := btcutil.DecodeWIF(secret)
wif, err := lbcutil.DecodeWIF(secret)
if err != nil {
t.Errorf("TestFilterInsertKey DecodeWIF failed: %v", err)
return
@ -222,7 +222,7 @@ func TestFilterInsertKey(t *testing.T) {
f := bloom.NewFilter(2, 0, 0.001, wire.BloomUpdateAll)
f.Add(wif.SerializePubKey())
f.Add(btcutil.Hash160(wif.SerializePubKey()))
f.Add(lbcutil.Hash160(wif.SerializePubKey()))
want, err := hex.DecodeString("038fc16b080000000000000001")
if err != nil {
@ -258,7 +258,7 @@ func TestFilterBloomMatch(t *testing.T) {
t.Errorf("TestFilterBloomMatch DecodeString failure: %v", err)
return
}
tx, err := btcutil.NewTxFromBytes(strBytes)
tx, err := lbcutil.NewTxFromBytes(strBytes)
if err != nil {
t.Errorf("TestFilterBloomMatch NewTxFromBytes failure: %v", err)
return
@ -293,7 +293,7 @@ func TestFilterBloomMatch(t *testing.T) {
0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70,
0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}
spendingTx, err := btcutil.NewTxFromBytes(spendingTxBytes)
spendingTx, err := lbcutil.NewTxFromBytes(spendingTxBytes)
if err != nil {
t.Errorf("TestFilterBloomMatch NewTxFromBytes failure: %v", err)
return
@ -585,7 +585,7 @@ func TestFilterInsertP2PubKeyOnly(t *testing.T) {
t.Errorf("TestFilterInsertP2PubKeyOnly DecodeString failed: %v", err)
return
}
block, err := btcutil.NewBlockFromBytes(blockBytes)
block, err := lbcutil.NewBlockFromBytes(blockBytes)
if err != nil {
t.Errorf("TestFilterInsertP2PubKeyOnly NewBlockFromBytes failed: %v", err)
return

View file

@ -5,10 +5,10 @@
package bloom
import (
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
)
// merkleBlock is used to house intermediate information needed to generate a
@ -79,7 +79,7 @@ func (m *merkleBlock) traverseAndBuild(height, pos uint32) {
// NewMerkleBlock returns a new *wire.MsgMerkleBlock and an array of the matched
// transaction index numbers based on the passed block and filter.
func NewMerkleBlock(block *btcutil.Block, filter *Filter) (*wire.MsgMerkleBlock, []uint32) {
func NewMerkleBlock(block *lbcutil.Block, filter *Filter) (*wire.MsgMerkleBlock, []uint32) {
numTx := uint32(len(block.Transactions()))
mBlock := merkleBlock{
numTx: numTx,

View file

@ -9,10 +9,10 @@ import (
"encoding/hex"
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/bloom"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
"github.com/lbryio/lbcutil/bloom"
)
func TestMerkleBlock3(t *testing.T) {
@ -29,7 +29,7 @@ func TestMerkleBlock3(t *testing.T) {
t.Errorf("TestMerkleBlock3 DecodeString failed: %v", err)
return
}
blk, err := btcutil.NewBlockFromBytes(blockBytes)
blk, err := lbcutil.NewBlockFromBytes(blockBytes)
if err != nil {
t.Errorf("TestMerkleBlock3 NewBlockFromBytes failed: %v", err)
return

View file

@ -7,7 +7,7 @@ package bloom_test
import (
"testing"
"github.com/btcsuite/btcutil/bloom"
"github.com/lbryio/lbcutil/bloom"
)
// TestMurmurHash3 ensure the MurmurHash3 function produces the correct hash

View file

@ -1,28 +1,28 @@
github.com/conformal/btcutil/bloom/murmurhash3.go MurmurHash3 100.00% (31/31)
github.com/conformal/btcutil/bloom/merkleblock.go NewMerkleBlock 100.00% (19/19)
github.com/conformal/btcutil/bloom/merkleblock.go merkleBlock.traverseAndBuild 100.00% (10/10)
github.com/conformal/btcutil/bloom/merkleblock.go merkleBlock.calcHash 100.00% (8/8)
github.com/conformal/btcutil/bloom/filter.go Filter.maybeAddOutpoint 100.00% (7/7)
github.com/conformal/btcutil/bloom/filter.go Filter.addOutPoint 100.00% (4/4)
github.com/conformal/btcutil/bloom/filter.go Filter.IsLoaded 100.00% (4/4)
github.com/conformal/btcutil/bloom/filter.go Filter.MsgFilterLoad 100.00% (4/4)
github.com/conformal/btcutil/bloom/filter.go Filter.matchesOutPoint 100.00% (4/4)
github.com/conformal/btcutil/bloom/filter.go Filter.MatchesOutPoint 100.00% (4/4)
github.com/conformal/btcutil/bloom/filter.go Filter.MatchTxAndUpdate 100.00% (4/4)
github.com/conformal/btcutil/bloom/filter.go Filter.Matches 100.00% (4/4)
github.com/conformal/btcutil/bloom/filter.go Filter.Add 100.00% (3/3)
github.com/conformal/btcutil/bloom/filter.go Filter.Reload 100.00% (3/3)
github.com/conformal/btcutil/bloom/filter.go Filter.Unload 100.00% (3/3)
github.com/conformal/btcutil/bloom/filter.go Filter.AddShaHash 100.00% (3/3)
github.com/conformal/btcutil/bloom/filter.go Filter.AddOutPoint 100.00% (3/3)
github.com/conformal/btcutil/bloom/filter.go minUint32 100.00% (3/3)
github.com/conformal/btcutil/bloom/filter.go Filter.hash 100.00% (2/2)
github.com/conformal/btcutil/bloom/merkleblock.go merkleBlock.calcTreeWidth 100.00% (1/1)
github.com/conformal/btcutil/bloom/filter.go LoadFilter 100.00% (1/1)
github.com/conformal/btcutil/bloom/filter.go Filter.matchTxAndUpdate 91.30% (21/23)
github.com/conformal/btcutil/bloom/filter.go Filter.matches 85.71% (6/7)
github.com/conformal/btcutil/bloom/filter.go NewFilter 81.82% (9/11)
github.com/conformal/btcutil/bloom/filter.go Filter.add 80.00% (4/5)
github.com/conformal/btcutil/bloom ---------------------------- 96.49% (165/171)
github.com/conformal/lbcutil/bloom/murmurhash3.go MurmurHash3 100.00% (31/31)
github.com/conformal/lbcutil/bloom/merkleblock.go NewMerkleBlock 100.00% (19/19)
github.com/conformal/lbcutil/bloom/merkleblock.go merkleBlock.traverseAndBuild 100.00% (10/10)
github.com/conformal/lbcutil/bloom/merkleblock.go merkleBlock.calcHash 100.00% (8/8)
github.com/conformal/lbcutil/bloom/filter.go Filter.maybeAddOutpoint 100.00% (7/7)
github.com/conformal/lbcutil/bloom/filter.go Filter.addOutPoint 100.00% (4/4)
github.com/conformal/lbcutil/bloom/filter.go Filter.IsLoaded 100.00% (4/4)
github.com/conformal/lbcutil/bloom/filter.go Filter.MsgFilterLoad 100.00% (4/4)
github.com/conformal/lbcutil/bloom/filter.go Filter.matchesOutPoint 100.00% (4/4)
github.com/conformal/lbcutil/bloom/filter.go Filter.MatchesOutPoint 100.00% (4/4)
github.com/conformal/lbcutil/bloom/filter.go Filter.MatchTxAndUpdate 100.00% (4/4)
github.com/conformal/lbcutil/bloom/filter.go Filter.Matches 100.00% (4/4)
github.com/conformal/lbcutil/bloom/filter.go Filter.Add 100.00% (3/3)
github.com/conformal/lbcutil/bloom/filter.go Filter.Reload 100.00% (3/3)
github.com/conformal/lbcutil/bloom/filter.go Filter.Unload 100.00% (3/3)
github.com/conformal/lbcutil/bloom/filter.go Filter.AddShaHash 100.00% (3/3)
github.com/conformal/lbcutil/bloom/filter.go Filter.AddOutPoint 100.00% (3/3)
github.com/conformal/lbcutil/bloom/filter.go minUint32 100.00% (3/3)
github.com/conformal/lbcutil/bloom/filter.go Filter.hash 100.00% (2/2)
github.com/conformal/lbcutil/bloom/merkleblock.go merkleBlock.calcTreeWidth 100.00% (1/1)
github.com/conformal/lbcutil/bloom/filter.go LoadFilter 100.00% (1/1)
github.com/conformal/lbcutil/bloom/filter.go Filter.matchTxAndUpdate 91.30% (21/23)
github.com/conformal/lbcutil/bloom/filter.go Filter.matches 85.71% (6/7)
github.com/conformal/lbcutil/bloom/filter.go NewFilter 81.82% (9/11)
github.com/conformal/lbcutil/bloom/filter.go Filter.add 80.00% (4/5)
github.com/conformal/lbcutil/bloom ---------------------------- 96.49% (165/171)

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
import (
"bytes"
@ -110,7 +110,7 @@ func NewTLSCertPair(organization string, validUntil time.Time, extraHosts []stri
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature |
x509.KeyUsageCertSign,
IsCA: true, // so can sign self.
IsCA: true, // so can sign self.
BasicConstraintsValid: true,
DNSNames: dnsNames,

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil_test
package lbcutil_test
import (
"crypto/x509"
@ -11,7 +11,7 @@ import (
"testing"
"time"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcutil"
//"github.com/davecgh/go-spew/spew"
)
@ -23,7 +23,7 @@ func TestNewTLSCertPair(t *testing.T) {
validUntil := time.Unix(time.Now().Add(10*365*24*time.Hour).Unix(), 0)
org := "test autogenerated cert"
extraHosts := []string{"testtlscert.bogus", "localhost", "127.0.0.1"}
cert, key, err := btcutil.NewTLSCertPair(org, validUntil, extraHosts)
cert, key, err := lbcutil.NewTLSCertPair(org, validUntil, extraHosts)
if err != nil {
t.Fatalf("failed with unexpected error: %v", err)
}

View file

@ -1,9 +1,7 @@
coinset
=======
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcutil/coinset)
Package coinset provides bitcoin-specific convenience functions for selecting
from and managing sets of unspent transaction outpoints (UTXOs).
@ -13,12 +11,6 @@ A comprehensive suite of tests is provided to ensure proper functionality. See
running a POSIX OS, you can run the `cov_report.sh` script for a real-time
report.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil/coinset
```
## Usage
Each unspent transaction outpoint is represented by the Coin interface. An
@ -63,9 +55,4 @@ msgTx := coinset.NewMsgTxWithInputCoins(selectedCoins)
```
The user can then create the msgTx.TxOut's as required, then sign the
transaction and transmit it to the network.
## License
Package coinset is licensed under the [copyfree](http://copyfree.org) ISC
License.
transaction and transmit it to the network.

View file

@ -9,16 +9,16 @@ import (
"errors"
"sort"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
)
// Coin represents a spendable transaction outpoint
type Coin interface {
Hash() *chainhash.Hash
Index() uint32
Value() btcutil.Amount
Value() lbcutil.Amount
PkScript() []byte
NumConfs() int64
ValueAge() int64
@ -39,7 +39,7 @@ type Coins interface {
// the CoinSet, otherwise the cached values will be incorrect.
type CoinSet struct {
coinList *list.List
totalValue btcutil.Amount
totalValue lbcutil.Amount
totalValueAge int64
}
@ -70,7 +70,7 @@ func (cs *CoinSet) Coins() []Coin {
}
// TotalValue returns the total value of the coins in the set.
func (cs *CoinSet) TotalValue() (value btcutil.Amount) {
func (cs *CoinSet) TotalValue() (value lbcutil.Amount) {
return cs.totalValue
}
@ -149,7 +149,7 @@ var (
// satisfiesTargetValue checks that the totalValue is either exactly the targetValue
// or is greater than the targetValue by at least the minChange amount.
func satisfiesTargetValue(targetValue, minChange, totalValue btcutil.Amount) bool {
func satisfiesTargetValue(targetValue, minChange, totalValue lbcutil.Amount) bool {
return (totalValue == targetValue || totalValue >= targetValue+minChange)
}
@ -165,7 +165,7 @@ func satisfiesTargetValue(targetValue, minChange, totalValue btcutil.Amount) boo
// It is important to note that the Coins being used as inputs need to have
// a constant ValueAge() during the execution of CoinSelect.
type CoinSelector interface {
CoinSelect(targetValue btcutil.Amount, coins []Coin) (Coins, error)
CoinSelect(targetValue lbcutil.Amount, coins []Coin) (Coins, error)
}
// MinIndexCoinSelector is a CoinSelector that attempts to construct a
@ -173,12 +173,12 @@ type CoinSelector interface {
// any number of lower indexes (as in the ordered array) over higher ones.
type MinIndexCoinSelector struct {
MaxInputs int
MinChangeAmount btcutil.Amount
MinChangeAmount lbcutil.Amount
}
// CoinSelect will attempt to select coins using the algorithm described
// in the MinIndexCoinSelector struct.
func (s MinIndexCoinSelector) CoinSelect(targetValue btcutil.Amount, coins []Coin) (Coins, error) {
func (s MinIndexCoinSelector) CoinSelect(targetValue lbcutil.Amount, coins []Coin) (Coins, error) {
cs := NewCoinSet(nil)
for n := 0; n < len(coins) && n < s.MaxInputs; n++ {
cs.PushCoin(coins[n])
@ -194,12 +194,12 @@ func (s MinIndexCoinSelector) CoinSelect(targetValue btcutil.Amount, coins []Coi
// that uses as few of the inputs as possible.
type MinNumberCoinSelector struct {
MaxInputs int
MinChangeAmount btcutil.Amount
MinChangeAmount lbcutil.Amount
}
// CoinSelect will attempt to select coins using the algorithm described
// in the MinNumberCoinSelector struct.
func (s MinNumberCoinSelector) CoinSelect(targetValue btcutil.Amount, coins []Coin) (Coins, error) {
func (s MinNumberCoinSelector) CoinSelect(targetValue lbcutil.Amount, coins []Coin) (Coins, error) {
sortedCoins := make([]Coin, 0, len(coins))
sortedCoins = append(sortedCoins, coins...)
sort.Sort(sort.Reverse(byAmount(sortedCoins)))
@ -216,12 +216,12 @@ func (s MinNumberCoinSelector) CoinSelect(targetValue btcutil.Amount, coins []Co
// block.
type MaxValueAgeCoinSelector struct {
MaxInputs int
MinChangeAmount btcutil.Amount
MinChangeAmount lbcutil.Amount
}
// CoinSelect will attempt to select coins using the algorithm described
// in the MaxValueAgeCoinSelector struct.
func (s MaxValueAgeCoinSelector) CoinSelect(targetValue btcutil.Amount, coins []Coin) (Coins, error) {
func (s MaxValueAgeCoinSelector) CoinSelect(targetValue lbcutil.Amount, coins []Coin) (Coins, error) {
sortedCoins := make([]Coin, 0, len(coins))
sortedCoins = append(sortedCoins, coins...)
sort.Sort(sort.Reverse(byValueAge(sortedCoins)))
@ -241,13 +241,13 @@ func (s MaxValueAgeCoinSelector) CoinSelect(targetValue btcutil.Amount, coins []
//
type MinPriorityCoinSelector struct {
MaxInputs int
MinChangeAmount btcutil.Amount
MinChangeAmount lbcutil.Amount
MinAvgValueAgePerInput int64
}
// CoinSelect will attempt to select coins using the algorithm described
// in the MinPriorityCoinSelector struct.
func (s MinPriorityCoinSelector) CoinSelect(targetValue btcutil.Amount, coins []Coin) (Coins, error) {
func (s MinPriorityCoinSelector) CoinSelect(targetValue lbcutil.Amount, coins []Coin) (Coins, error) {
possibleCoins := make([]Coin, 0, len(coins))
possibleCoins = append(possibleCoins, coins...)
@ -343,10 +343,10 @@ func (a byAmount) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byAmount) Less(i, j int) bool { return a[i].Value() < a[j].Value() }
// SimpleCoin defines a concrete instance of Coin that is backed by a
// btcutil.Tx, a specific outpoint index, and the number of confirmations
// lbcutil.Tx, a specific outpoint index, and the number of confirmations
// that transaction has had.
type SimpleCoin struct {
Tx *btcutil.Tx
Tx *lbcutil.Tx
TxIndex uint32
TxNumConfs int64
}
@ -370,8 +370,8 @@ func (c *SimpleCoin) txOut() *wire.TxOut {
}
// Value returns the value of the Coin
func (c *SimpleCoin) Value() btcutil.Amount {
return btcutil.Amount(c.txOut().Value)
func (c *SimpleCoin) Value() lbcutil.Amount {
return lbcutil.Amount(c.txOut().Value)
}
// PkScript returns the outpoint script of the Coin.

View file

@ -11,27 +11,27 @@ import (
"fmt"
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/coinset"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
"github.com/lbryio/lbcutil/coinset"
)
type TestCoin struct {
TxHash *chainhash.Hash
TxIndex uint32
TxValue btcutil.Amount
TxValue lbcutil.Amount
TxNumConfs int64
}
func (c *TestCoin) Hash() *chainhash.Hash { return c.TxHash }
func (c *TestCoin) Index() uint32 { return c.TxIndex }
func (c *TestCoin) Value() btcutil.Amount { return c.TxValue }
func (c *TestCoin) Value() lbcutil.Amount { return c.TxValue }
func (c *TestCoin) PkScript() []byte { return nil }
func (c *TestCoin) NumConfs() int64 { return c.TxNumConfs }
func (c *TestCoin) ValueAge() int64 { return int64(c.TxValue) * c.TxNumConfs }
func NewCoin(index int64, value btcutil.Amount, numConfs int64) coinset.Coin {
func NewCoin(index int64, value lbcutil.Amount, numConfs int64) coinset.Coin {
h := sha256.New()
h.Write([]byte(fmt.Sprintf("%d", index)))
hash, _ := chainhash.NewHash(h.Sum(nil))
@ -47,7 +47,7 @@ func NewCoin(index int64, value btcutil.Amount, numConfs int64) coinset.Coin {
type coinSelectTest struct {
selector coinset.CoinSelector
inputCoins []coinset.Coin
targetValue btcutil.Amount
targetValue lbcutil.Amount
expectedCoins []coinset.Coin
expectedError error
}
@ -225,12 +225,12 @@ var (
testSimpleCoinNumConfs = int64(1)
testSimpleCoinTxHash = "9b5965c86de51d5dc824e179a05cf232db78c80ae86ca9d7cb2a655b5e19c1e2"
testSimpleCoinTxHex = "0100000001a214a110f79e4abe073865ea5b3745c6e82c913bad44be70652804a5e4003b0a010000008c493046022100edd18a69664efa57264be207100c203e6cade1888cbb88a0ad748548256bb2f0022100f1027dc2e6c7f248d78af1dd90027b5b7d8ec563bb62aa85d4e74d6376f3868c0141048f3757b65ed301abd1b0e8942d1ab5b50594d3314cff0299f300c696376a0a9bf72e74710a8af7a5372d4af4bb519e2701a094ef48c8e48e3b65b28502452dceffffffff02e0673500000000001976a914686dd149a79b4a559d561fbc396d3e3c6628b98d88ace86ef102000000001976a914ac3f995655e81b875b38b64351d6f896ddbfc68588ac00000000"
testSimpleCoinTxValue0 = btcutil.Amount(3500000)
testSimpleCoinTxValue0 = lbcutil.Amount(3500000)
testSimpleCoinTxValueAge0 = int64(testSimpleCoinTxValue0) * testSimpleCoinNumConfs
testSimpleCoinTxPkScript0Hex = "76a914686dd149a79b4a559d561fbc396d3e3c6628b98d88ac"
testSimpleCoinTxPkScript0Bytes, _ = hex.DecodeString(testSimpleCoinTxPkScript0Hex)
testSimpleCoinTxBytes, _ = hex.DecodeString(testSimpleCoinTxHex)
testSimpleCoinTx, _ = btcutil.NewTxFromBytes(testSimpleCoinTxBytes)
testSimpleCoinTx, _ = lbcutil.NewTxFromBytes(testSimpleCoinTxBytes)
testSimpleCoin = &coinset.SimpleCoin{
Tx: testSimpleCoinTx,
TxIndex: 0,

View file

@ -1,31 +1,31 @@
github.com/conformal/btcutil/coinset/coins.go MinPriorityCoinSelector.CoinSelect 100.00% (39/39)
github.com/conformal/btcutil/coinset/coins.go NewMsgTxWithInputCoins 100.00% (6/6)
github.com/conformal/btcutil/coinset/coins.go MinIndexCoinSelector.CoinSelect 100.00% (6/6)
github.com/conformal/btcutil/coinset/coins.go CoinSet.removeElement 100.00% (5/5)
github.com/conformal/btcutil/coinset/coins.go NewCoinSet 100.00% (4/4)
github.com/conformal/btcutil/coinset/coins.go CoinSet.Coins 100.00% (4/4)
github.com/conformal/btcutil/coinset/coins.go CoinSet.PopCoin 100.00% (4/4)
github.com/conformal/btcutil/coinset/coins.go CoinSet.ShiftCoin 100.00% (4/4)
github.com/conformal/btcutil/coinset/coins.go MinNumberCoinSelector.CoinSelect 100.00% (4/4)
github.com/conformal/btcutil/coinset/coins.go MaxValueAgeCoinSelector.CoinSelect 100.00% (4/4)
github.com/conformal/btcutil/coinset/coins.go CoinSet.PushCoin 100.00% (3/3)
github.com/conformal/btcutil/coinset/coins.go CoinSet.TotalValueAge 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go SimpleCoin.NumConfs 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go SimpleCoin.ValueAge 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go CoinSet.TotalValue 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go byValueAge.Len 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go byValueAge.Swap 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go byValueAge.Less 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go byAmount.Len 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go byAmount.Swap 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go byAmount.Less 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go SimpleCoin.Hash 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go SimpleCoin.Index 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go SimpleCoin.txOut 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go SimpleCoin.Value 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go SimpleCoin.PkScript 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go CoinSet.Num 100.00% (1/1)
github.com/conformal/btcutil/coinset/coins.go satisfiesTargetValue 100.00% (1/1)
github.com/conformal/btcutil/coinset ---------------------------------- 100.00% (100/100)
github.com/conformal/lbcutil/coinset/coins.go MinPriorityCoinSelector.CoinSelect 100.00% (39/39)
github.com/conformal/lbcutil/coinset/coins.go NewMsgTxWithInputCoins 100.00% (6/6)
github.com/conformal/lbcutil/coinset/coins.go MinIndexCoinSelector.CoinSelect 100.00% (6/6)
github.com/conformal/lbcutil/coinset/coins.go CoinSet.removeElement 100.00% (5/5)
github.com/conformal/lbcutil/coinset/coins.go NewCoinSet 100.00% (4/4)
github.com/conformal/lbcutil/coinset/coins.go CoinSet.Coins 100.00% (4/4)
github.com/conformal/lbcutil/coinset/coins.go CoinSet.PopCoin 100.00% (4/4)
github.com/conformal/lbcutil/coinset/coins.go CoinSet.ShiftCoin 100.00% (4/4)
github.com/conformal/lbcutil/coinset/coins.go MinNumberCoinSelector.CoinSelect 100.00% (4/4)
github.com/conformal/lbcutil/coinset/coins.go MaxValueAgeCoinSelector.CoinSelect 100.00% (4/4)
github.com/conformal/lbcutil/coinset/coins.go CoinSet.PushCoin 100.00% (3/3)
github.com/conformal/lbcutil/coinset/coins.go CoinSet.TotalValueAge 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go SimpleCoin.NumConfs 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go SimpleCoin.ValueAge 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go CoinSet.TotalValue 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go byValueAge.Len 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go byValueAge.Swap 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go byValueAge.Less 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go byAmount.Len 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go byAmount.Swap 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go byAmount.Less 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go SimpleCoin.Hash 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go SimpleCoin.Index 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go SimpleCoin.txOut 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go SimpleCoin.Value 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go SimpleCoin.PkScript 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go CoinSet.Num 100.00% (1/1)
github.com/conformal/lbcutil/coinset/coins.go satisfiesTargetValue 100.00% (1/1)
github.com/conformal/lbcutil/coinset ---------------------------------- 100.00% (100/100)

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
const (
// SatoshiPerBitcent is the number of satoshi in one bitcoin cent.
@ -12,5 +12,5 @@ const (
SatoshiPerBitcoin = 1e8
// MaxSatoshi is the maximum transaction amount allowed in satoshi.
MaxSatoshi = 21e6 * SatoshiPerBitcoin
MaxSatoshi = 21e9 * SatoshiPerBitcoin
)

6
doc.go
View file

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
/*
Package btcutil provides bitcoin-specific convenience functions and types.
Package lbcutil provides bitcoin-specific convenience functions and types.
Block Overview
@ -36,11 +36,11 @@ To decode/encode an address:
"e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d57" +
"8a4c702b6bf11d5f"
defaultNet := &chaincfg.MainNetParams
addr, err := btcutil.DecodeAddress(addrString, defaultNet)
addr, err := lbcutil.DecodeAddress(addrString, defaultNet)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(addr.EncodeAddress())
*/
package btcutil
package lbcutil

View file

@ -1,21 +1,21 @@
package btcutil_test
package lbcutil_test
import (
"fmt"
"math"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcutil"
)
func ExampleAmount() {
a := btcutil.Amount(0)
a := lbcutil.Amount(0)
fmt.Println("Zero Satoshi:", a)
a = btcutil.Amount(1e8)
a = lbcutil.Amount(1e8)
fmt.Println("100,000,000 Satoshis:", a)
a = btcutil.Amount(1e5)
a = lbcutil.Amount(1e5)
fmt.Println("100,000 Satoshis:", a)
// Output:
// Zero Satoshi: 0 BTC
@ -24,28 +24,28 @@ func ExampleAmount() {
}
func ExampleNewAmount() {
amountOne, err := btcutil.NewAmount(1)
amountOne, err := lbcutil.NewAmount(1)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(amountOne) //Output 1
amountFraction, err := btcutil.NewAmount(0.01234567)
amountFraction, err := lbcutil.NewAmount(0.01234567)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(amountFraction) //Output 2
amountZero, err := btcutil.NewAmount(0)
amountZero, err := lbcutil.NewAmount(0)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(amountZero) //Output 3
amountNaN, err := btcutil.NewAmount(math.NaN())
amountNaN, err := lbcutil.NewAmount(math.NaN())
if err != nil {
fmt.Println(err)
return
@ -59,13 +59,13 @@ func ExampleNewAmount() {
}
func ExampleAmount_unitConversions() {
amount := btcutil.Amount(44433322211100)
amount := lbcutil.Amount(44433322211100)
fmt.Println("Satoshi to kBTC:", amount.Format(btcutil.AmountKiloBTC))
fmt.Println("Satoshi to kBTC:", amount.Format(lbcutil.AmountKiloBTC))
fmt.Println("Satoshi to BTC:", amount)
fmt.Println("Satoshi to MilliBTC:", amount.Format(btcutil.AmountMilliBTC))
fmt.Println("Satoshi to MicroBTC:", amount.Format(btcutil.AmountMicroBTC))
fmt.Println("Satoshi to Satoshi:", amount.Format(btcutil.AmountSatoshi))
fmt.Println("Satoshi to MilliBTC:", amount.Format(lbcutil.AmountMilliBTC))
fmt.Println("Satoshi to MicroBTC:", amount.Format(lbcutil.AmountMicroBTC))
fmt.Println("Satoshi to Satoshi:", amount.Format(lbcutil.AmountSatoshi))
// Output:
// Satoshi to kBTC: 444.333222111 kBTC

View file

@ -1,24 +1,9 @@
gcs
==========
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)]
(https://travis-ci.org/btcsuite/btcutil) [![ISC License]
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://godoc.org/github.com/btcsuite/btcutil/gcs?status.png)]
(http://godoc.org/github.com/btcsuite/btcutil/gcs)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
Package gcs provides an API for building and using a Golomb-coded set filter
similar to that described [here](http://giovanni.bajo.it/post/47119962313/golomb-coded-sets-smaller-than-bloom-filters).
A comprehensive suite of tests is provided to ensure proper functionality.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil/gcs
```
## License
Package gcs is licensed under the [copyfree](http://copyfree.org) ISC
License.
A comprehensive suite of tests is provided to ensure proper functionality.

View file

@ -10,10 +10,10 @@ import (
"fmt"
"math"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil/gcs"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil/gcs"
)
const (

View file

@ -9,13 +9,13 @@ import (
"encoding/hex"
"testing"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/gcs"
"github.com/btcsuite/btcutil/gcs/builder"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
"github.com/lbryio/lbcutil/gcs"
"github.com/lbryio/lbcutil/gcs/builder"
)
var (
@ -79,8 +79,8 @@ func TestUseBlockHash(t *testing.T) {
Index: 4321,
}
// btcutil.Address
addr, err := btcutil.DecodeAddress(testAddr, &chaincfg.MainNetParams)
// lbcutil.Address
addr, err := lbcutil.DecodeAddress(testAddr, &chaincfg.MainNetParams)
if err != nil {
t.Fatalf("Address decode failed: %s", err.Error())
}

View file

@ -12,7 +12,7 @@ import (
"sort"
"github.com/aead/siphash"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
"github.com/kkdai/bstream"
)

View file

@ -11,7 +11,7 @@ import (
"math/rand"
"testing"
"github.com/btcsuite/btcutil/gcs"
"github.com/lbryio/lbcutil/gcs"
)
var (

View file

@ -10,7 +10,7 @@ import (
"math/rand"
"testing"
"github.com/btcsuite/btcutil/gcs"
"github.com/lbryio/lbcutil/gcs"
)
func genRandFilterElements(numElements uint) ([][]byte, error) {

12
go.mod
View file

@ -1,11 +1,11 @@
module github.com/btcsuite/btcutil
module github.com/lbryio/lbcutil
go 1.13
go 1.16
require (
github.com/aead/siphash v1.0.1
github.com/btcsuite/btcd v0.20.1-beta
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d
github.com/davecgh/go-spew v1.1.1
github.com/kkdai/bstream v1.0.0
github.com/lbryio/lbcd v0.22.100-beta
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
)

539
go.sum
View file

@ -1,54 +1,555 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo=
github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ=
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0=
github.com/btcsuite/goleveldb v1.0.0 h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4=
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/snappy-go v1.0.0 h1:ZxaA6lo2EpxGddsA8JwWOcxlzRybb444sgmeJQMJGQE=
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495 h1:6IyqGr3fnd0tM3YxipK27TUskaOVUjU2nG45yzwcQKY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4=
github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM=
github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y=
github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/cockroachdb/pebble v0.0.0-20210525181856-e45797baeb78 h1:bsZKpvDmUKiBm14kDi8sMqG3bRsfIJ64NwuaAr/8MZs=
github.com/cockroachdb/pebble v0.0.0-20210525181856-e45797baeb78/go.mod h1:1XpB4cLQcF189RAcWi4gUc110zJgtOfT7SVNGY8sOe0=
github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw=
github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/fgprof v0.9.1/go.mod h1:7/HK6JFtFaARhIljgP2IV8rJLIoHDoOYoUphsnGvqxE=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf h1:gFVkHXmVAhEbxZVDln5V9GKrLaluNoFHDbrZwAWZgws=
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20200615235658-03e1cf38a040/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8=
github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/lbryio/lbcd v0.22.100-beta h1:6nv+G+MxxWqIbBLEPkSkc2Z3qhqrP8vVDHkc8+UWyv4=
github.com/lbryio/lbcd v0.22.100-beta/go.mod h1:u8SaFX4xdGMMR5xasBGfgApC8pvD4rnK2OujZnrq5gs=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shirou/gopsutil/v3 v3.21.7/go.mod h1:RGl11Y7XMTQPmHh8F0ayC6haKNBgH4PXMJuTAcMOlz4=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tklauser/go-sysconf v0.3.7/go.mod h1:JZIdXh4RmBvZDBZ41ld2bGxRV3n4daiiqA3skYhAoQ4=
github.com/tklauser/numcpus v0.2.3/go.mod h1:vpEPS/JC+oZGGQ/My/vJnNsvMDQL6PwOqt8dsCw5j+E=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vmihailenco/msgpack/v5 v5.3.2/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d h1:2+ZP7EfsZV7Vvmx3TIqSlSzATMkTAKqM14YGFPoSKjI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20200513190911-00229845015e h1:rMqLP+9XLy+LdbCXHjJHAmTfXCr93W7oruWA6Hq1Alc=
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

View file

@ -9,40 +9,38 @@
# 7. race detector (http://blog.golang.org/race-detector)
# 8. test coverage (http://blog.golang.org/cover)
#
# gometalint (github.com/alecthomas/gometalinter) is used to run each each
# static checker.
set -ex
# Automatic checks
test -z "$(gometalinter --disable-all \
--enable=gofmt \
--enable=goimports \
--enable=golint \
--enable=vet \
--enable=gosimple \
--enable=unconvert \
--deadline=120s ./... | grep -v 'ExampleNew' 2>&1 | tee /dev/stderr)"
env GORACE="halt_on_error=1" go test -race ./...
for i in $(find . -name go.mod -type f -print); do
module=$(dirname ${i})
echo "==> ${module}"
# Run test coverage on each subdirectories and merge the coverage profile.
echo "mode: count" > profile.cov
# Standard go tooling behavior is to ignore dirs with leading underscores.
for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d);
do
if ls $dir/*.go &> /dev/null; then
go test -covermode=count -coverprofile=$dir/profile.tmp $dir
if [ -f $dir/profile.tmp ]; then
cat $dir/profile.tmp | tail -n +2 >> profile.cov
rm $dir/profile.tmp
MODNAME=$(echo $module | sed -E -e "s/^$ROOTPATHPATTERN//" \
-e 's,^/,,' -e 's,/v[0-9]+$,,')
if [ -z "$MODNAME" ]; then
MODNAME=.
fi
fi
# run tests
(cd $MODNAME &&
echo "mode: atomic" > profile.cov && \
env GORACE=halt_on_error=1 go test -race -covermode=atomic -coverprofile=profile.tmp ./... && \
cat profile.tmp | tail -n +2 >> profile.cov && \
rm profile.tmp && \
go tool cover -func profile.cov
)
# check linters
(cd $MODNAME && \
go mod download && \
golangci-lint run --deadline=10m --disable-all \
--enable=gofmt \
--enable=goimports \
--enable=golint \
--enable=govet \
--enable=gosimple \
--enable=unconvert
)
done
go tool cover -func profile.cov
# To submit the test coverage result to coveralls.io,
# use goveralls (https://github.com/mattn/goveralls)
# goveralls -coverprofile=profile.cov -service=travis-ci

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
import (
"crypto/sha256"

View file

@ -1,9 +1,7 @@
hdkeychain
==========
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcutil/hdkeychain)
Package hdkeychain provides an API for bitcoin hierarchical deterministic
extended keys (BIP0032).
@ -24,7 +22,7 @@ report.
keys
- Support for custom networks by registering them with chaincfg
- Obtaining the underlying EC pubkeys, EC privkeys, and associated bitcoin
addresses ties in seamlessly with existing btcec and btcutil types which
addresses ties in seamlessly with existing btcec and lbcutil types which
provide powerful tools for working with them to do things like sign
transations and generate payment scripts
- Uses the btcec package which is highly optimized for secp256k1
@ -36,24 +34,13 @@ report.
- Comprehensive test coverage including the BIP0032 test vectors
- Benchmarks
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil/hdkeychain
```
## Examples
* [NewMaster Example](http://godoc.org/github.com/btcsuite/btcutil/hdkeychain#example-NewMaster)
* [NewMaster Example](http://godoc.org/github.com/lbryio/lbcutil/hdkeychain#example-NewMaster)
Demonstrates how to generate a cryptographically random seed then use it to
create a new master node (extended key).
* [Default Wallet Layout Example](http://godoc.org/github.com/btcsuite/btcutil/hdkeychain#example-package--DefaultWalletLayout)
* [Default Wallet Layout Example](http://godoc.org/github.com/lbryio/lbcutil/hdkeychain#example-package--DefaultWalletLayout)
Demonstrates the default hierarchical deterministic wallet layout as described
in BIP0032.
* [Audits Use Case Example](http://godoc.org/github.com/btcsuite/btcutil/hdkeychain#example-package--Audits)
Demonstrates the audits use case in BIP0032.
## License
Package hdkeychain is licensed under the [copyfree](http://copyfree.org) ISC
License.
* [Audits Use Case Example](http://godoc.org/github.com/lbryio/lbcutil/hdkeychain#example-package--Audits)
Demonstrates the audits use case in BIP0032.

View file

@ -7,7 +7,7 @@ package hdkeychain_test
import (
"testing"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/lbryio/lbcutil/hdkeychain"
)
// bip0032MasterPriv1 is the master private extended key from the first set of
@ -26,7 +26,7 @@ func BenchmarkDeriveHardened(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
masterKey.Child(hdkeychain.HardenedKeyStart)
masterKey.Derive(hdkeychain.HardenedKeyStart)
}
}
@ -41,7 +41,7 @@ func BenchmarkDeriveNormal(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
masterKey.Child(0)
masterKey.Derive(0)
}
}

View file

@ -39,14 +39,14 @@ create a random seed for use with the NewMaster function.
Deriving Children
Once you have created a tree root (or have deserialized an extended key as
discussed later), the child extended keys can be derived by using the Child
function. The Child function supports deriving both normal (non-hardened) and
discussed later), the child extended keys can be derived by using the Derive
function. The Derive function supports deriving both normal (non-hardened) and
hardened child extended keys. In order to derive a hardened extended key, use
the HardenedKeyStart constant + the hardened key number as the index to the
Child function. This provides the ability to cascade the keys into a tree and
Derive function. This provides the ability to cascade the keys into a tree and
hence generate the hierarchical deterministic key chains.
Normal vs Hardened Child Extended Keys
Normal vs Hardened Derived Extended Keys
A private extended key can be used to derive both hardened and non-hardened
(normal) child private and public extended keys. A public extended key can only

View file

@ -7,8 +7,8 @@ package hdkeychain_test
import (
"fmt"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcutil/hdkeychain"
)
// This example demonstrates how to generate a cryptographically random seed
@ -71,7 +71,7 @@ func Example_defaultWalletLayout() {
// Derive the extended key for account 0. This gives the path:
// m/0H
acct0, err := masterKey.Child(hdkeychain.HardenedKeyStart + 0)
acct0, err := masterKey.Derive(hdkeychain.HardenedKeyStart + 0)
if err != nil {
fmt.Println(err)
return
@ -80,7 +80,7 @@ func Example_defaultWalletLayout() {
// Derive the extended key for the account 0 external chain. This
// gives the path:
// m/0H/0
acct0Ext, err := acct0.Child(0)
acct0Ext, err := acct0.Derive(0)
if err != nil {
fmt.Println(err)
return
@ -89,7 +89,7 @@ func Example_defaultWalletLayout() {
// Derive the extended key for the account 0 internal chain. This gives
// the path:
// m/0H/1
acct0Int, err := acct0.Child(1)
acct0Int, err := acct0.Derive(1)
if err != nil {
fmt.Println(err)
return
@ -101,7 +101,7 @@ func Example_defaultWalletLayout() {
// Derive the 10th extended key for the account 0 external chain. This
// gives the path:
// m/0H/0/10
acct0Ext10, err := acct0Ext.Child(10)
acct0Ext10, err := acct0Ext.Derive(10)
if err != nil {
fmt.Println(err)
return
@ -110,7 +110,7 @@ func Example_defaultWalletLayout() {
// Derive the 1st extended key for the account 0 internal chain. This
// gives the path:
// m/0H/1/0
acct0Int0, err := acct0Int.Child(0)
acct0Int0, err := acct0Int.Derive(0)
if err != nil {
fmt.Println(err)
return

View file

@ -18,11 +18,11 @@ import (
"fmt"
"math/big"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/base58"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcutil"
"github.com/lbryio/lbcutil/base58"
)
const (
@ -30,8 +30,8 @@ const (
// to a master node.
RecommendedSeedLen = 32 // 256 bits
// HardenedKeyStart is the index at which a hardended key starts. Each
// extended key has 2^31 normal child keys and 2^31 hardned child keys.
// HardenedKeyStart is the index at which a hardened key starts. Each
// extended key has 2^31 normal child keys and 2^31 hardened child keys.
// Thus the range for normal child keys is [0, 2^31 - 1] and the range
// for hardened child keys is [2^31, 2^32 - 1].
HardenedKeyStart = 0x80000000 // 2^31
@ -119,8 +119,8 @@ type ExtendedKey struct {
// NewExtendedKey returns a new instance of an extended key with the given
// fields. No error checking is performed here as it's only intended to be a
// convenience method used to create a populated struct. This function should
// only by used by applications that need to create custom ExtendedKeys. All
// other applications should just use NewMaster, Child, or Neuter.
// only be used by applications that need to create custom ExtendedKeys. All
// other applications should just use NewMaster, Derive, or Neuter.
func NewExtendedKey(version, key, chainCode, parentFP []byte, depth uint8,
childNum uint32, isPrivate bool) *ExtendedKey {
@ -179,20 +179,40 @@ func (k *ExtendedKey) Depth() uint8 {
return k.depth
}
// Version returns the extended key's hardened derivation version. This can be
// used to identify the extended key's type.
func (k *ExtendedKey) Version() []byte {
return k.version
}
// ParentFingerprint returns a fingerprint of the parent extended key from which
// this one was derived.
func (k *ExtendedKey) ParentFingerprint() uint32 {
return binary.BigEndian.Uint32(k.parentFP)
}
// Child returns a derived child extended key at the given index. When this
// extended key is a private extended key (as determined by the IsPrivate
// ChainCode returns the chain code part of this extended key.
//
// It is identical for both public and private extended keys.
func (k *ExtendedKey) ChainCode() []byte {
return append([]byte{}, k.chainCode...)
}
// Derive returns a derived child extended key at the given index.
//
// IMPORTANT: if you were previously using the Child method, this method is incompatible.
// The Child method had a BIP-32 standard compatibility issue. You have to check whether
// any hardened derivations in your derivation path are affected by this issue, via the
// IsAffectedByIssue172 method and migrate the wallet if so. This method does conform
// to the standard. If you need the old behavior, use DeriveNonStandard.
//
// When this extended key is a private extended key (as determined by the IsPrivate
// function), a private extended key will be derived. Otherwise, the derived
// extended key will be also be a public extended key.
//
// When the index is greater to or equal than the HardenedKeyStart constant, the
// derived extended key will be a hardened extended key. It is only possible to
// derive a hardended extended key from a private extended key. Consequently,
// derive a hardened extended key from a private extended key. Consequently,
// this function will return ErrDeriveHardFromPublic if a hardened child
// extended key is requested from a public extended key.
//
@ -206,7 +226,7 @@ func (k *ExtendedKey) ParentFingerprint() uint32 {
// index does not derive to a usable child. The ErrInvalidChild error will be
// returned if this should occur, and the caller is expected to ignore the
// invalid child and simply increment to the next index.
func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) {
func (k *ExtendedKey) Derive(i uint32) (*ExtendedKey, error) {
// Prevent derivation of children beyond the max allowed depth.
if k.depth == maxUint8 {
return nil, ErrDeriveBeyondMaxDepth
@ -241,7 +261,9 @@ func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) {
// When the child is a hardened child, the key is known to be a
// private key due to the above early return. Pad it with a
// leading zero as required by [BIP32] for deriving the child.
copy(data[1:], k.key)
// Additionally, right align it if it's shorter than 32 bytes.
offset := 33 - len(k.key)
copy(data[offset:], k.key)
} else {
// Case #2 or #3.
// This is either a public or private extended key, but in
@ -324,11 +346,88 @@ func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) {
// The fingerprint of the parent for the derived child is the first 4
// bytes of the RIPEMD160(SHA256(parentPubKey)).
parentFP := btcutil.Hash160(k.pubKeyBytes())[:4]
parentFP := lbcutil.Hash160(k.pubKeyBytes())[:4]
return NewExtendedKey(k.version, childKey, childChainCode, parentFP,
k.depth+1, i, isPrivate), nil
}
// Returns true if this key was affected by the BIP-32 issue in the Child
// method (since renamed to DeriveNonStandard).
func (k *ExtendedKey) IsAffectedByIssue172() bool {
return len(k.key) < 32
}
// Deprecated: This is a non-standard derivation that is affected by issue #172.
// 1-of-256 hardened derivations will be wrong. See note in the Derive method
// and IsAffectedByIssue172.
func (k *ExtendedKey) DeriveNonStandard(i uint32) (*ExtendedKey, error) {
if k.depth == maxUint8 {
return nil, ErrDeriveBeyondMaxDepth
}
isChildHardened := i >= HardenedKeyStart
if !k.isPrivate && isChildHardened {
return nil, ErrDeriveHardFromPublic
}
keyLen := 33
data := make([]byte, keyLen+4)
if isChildHardened {
copy(data[1:], k.key)
} else {
copy(data, k.pubKeyBytes())
}
binary.BigEndian.PutUint32(data[keyLen:], i)
hmac512 := hmac.New(sha512.New, k.chainCode)
hmac512.Write(data)
ilr := hmac512.Sum(nil)
il := ilr[:len(ilr)/2]
childChainCode := ilr[len(ilr)/2:]
ilNum := new(big.Int).SetBytes(il)
if ilNum.Cmp(btcec.S256().N) >= 0 || ilNum.Sign() == 0 {
return nil, ErrInvalidChild
}
var isPrivate bool
var childKey []byte
if k.isPrivate {
keyNum := new(big.Int).SetBytes(k.key)
ilNum.Add(ilNum, keyNum)
ilNum.Mod(ilNum, btcec.S256().N)
childKey = ilNum.Bytes()
isPrivate = true
} else {
ilx, ily := btcec.S256().ScalarBaseMult(il)
if ilx.Sign() == 0 || ily.Sign() == 0 {
return nil, ErrInvalidChild
}
pubKey, err := btcec.ParsePubKey(k.key, btcec.S256())
if err != nil {
return nil, err
}
childX, childY := btcec.S256().Add(ilx, ily, pubKey.X, pubKey.Y)
pk := btcec.PublicKey{Curve: btcec.S256(), X: childX, Y: childY}
childKey = pk.SerializeCompressed()
}
parentFP := lbcutil.Hash160(k.pubKeyBytes())[:4]
return NewExtendedKey(k.version, childKey, childChainCode, parentFP,
k.depth+1, i, isPrivate), nil
}
// ChildNum returns the index at which the child extended key was derived.
//
// Extended keys with ChildNum value between 0 and 2^31-1 are normal child
// keys, and those with a value between 2^31 and 2^32-1 are hardened keys.
func (k *ExtendedKey) ChildIndex() uint32 {
return k.childNum
}
// Neuter returns a new extended public key from this extended private key. The
// same extended key will be returned unaltered if it is already an extended
// public key.
@ -357,6 +456,36 @@ func (k *ExtendedKey) Neuter() (*ExtendedKey, error) {
k.depth, k.childNum, false), nil
}
// CloneWithVersion returns a new extended key cloned from this extended key,
// but using the provided HD version bytes. The version must be a private HD
// key ID for an extended private key, and a public HD key ID for an extended
// public key.
//
// This method creates a new copy and therefore does not mutate the original
// extended key instance.
//
// Unlike Neuter(), this does NOT convert an extended private key to an
// extended public key. It is particularly useful for converting between
// standard BIP0032 extended keys (serializable to xprv/xpub) and keys based
// on the SLIP132 standard (serializable to yprv/ypub, zprv/zpub, etc.).
//
// References:
// [SLIP132]: SLIP-0132 - Registered HD version bytes for BIP-0032
// https://github.com/satoshilabs/slips/blob/master/slip-0132.md
func (k *ExtendedKey) CloneWithVersion(version []byte) (*ExtendedKey, error) {
if len(version) != 4 {
// TODO: The semantically correct error to return here is
// ErrInvalidHDKeyID (introduced in btcsuite/btcd#1617). Update the
// error type once available in a stable btcd / chaincfg release.
return nil, chaincfg.ErrUnknownHDKeyID
}
// Initialize a new extended key instance with the same fields as the
// current extended private/public key and the provided HD version bytes.
return NewExtendedKey(version, k.key, k.chainCode, k.parentFP,
k.depth, k.childNum, k.isPrivate), nil
}
// ECPubKey converts the extended key to a btcec public key and returns it.
func (k *ExtendedKey) ECPubKey() (*btcec.PublicKey, error) {
return btcec.ParsePubKey(k.pubKeyBytes(), btcec.S256())
@ -377,9 +506,9 @@ func (k *ExtendedKey) ECPrivKey() (*btcec.PrivateKey, error) {
// Address converts the extended key to a standard bitcoin pay-to-pubkey-hash
// address for the passed network.
func (k *ExtendedKey) Address(net *chaincfg.Params) (*btcutil.AddressPubKeyHash, error) {
pkHash := btcutil.Hash160(k.pubKeyBytes())
return btcutil.NewAddressPubKeyHash(pkHash, net)
func (k *ExtendedKey) Address(net *chaincfg.Params) (*lbcutil.AddressPubKeyHash, error) {
pkHash := lbcutil.Hash160(k.pubKeyBytes())
return lbcutil.NewAddressPubKeyHash(pkHash, net)
}
// paddedAppend appends the src byte slice to dst, returning the new slice.

View file

@ -10,13 +10,14 @@ package hdkeychain
import (
"bytes"
"encoding/binary"
"encoding/hex"
"errors"
"math"
"reflect"
"testing"
"github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg"
)
// TestBIP0032Vectors tests the vectors provided by [BIP32] to ensure the
@ -224,7 +225,7 @@ tests:
for _, childNum := range test.path {
var err error
extKey, err = extKey.Child(childNum)
extKey, err = extKey.Derive(childNum)
if err != nil {
t.Errorf("err: %v", err)
continue tests
@ -381,7 +382,7 @@ tests:
for _, childNum := range test.path {
var err error
extKey, err = extKey.Child(childNum)
extKey, err = extKey.Derive(childNum)
if err != nil {
t.Errorf("err: %v", err)
continue tests
@ -390,7 +391,7 @@ tests:
privStr := extKey.String()
if privStr != test.wantPriv {
t.Errorf("Child #%d (%s): mismatched serialized "+
t.Errorf("Derive #%d (%s): mismatched serialized "+
"private extended key -- got: %s, want: %s", i,
test.name, privStr, test.wantPriv)
continue
@ -500,7 +501,7 @@ tests:
for _, childNum := range test.path {
var err error
extKey, err = extKey.Child(childNum)
extKey, err = extKey.Derive(childNum)
if err != nil {
t.Errorf("err: %v", err)
continue tests
@ -509,7 +510,7 @@ tests:
pubStr := extKey.String()
if pubStr != test.wantPub {
t.Errorf("Child #%d (%s): mismatched serialized "+
t.Errorf("Derive #%d (%s): mismatched serialized "+
"public extended key -- got: %s, want: %s", i,
test.name, pubStr, test.wantPub)
continue
@ -517,8 +518,8 @@ tests:
}
}
// TestGenenerateSeed ensures the GenerateSeed function works as intended.
func TestGenenerateSeed(t *testing.T) {
// TestGenerateSeed ensures the GenerateSeed function works as intended.
func TestGenerateSeed(t *testing.T) {
wantErr := errors.New("seed length must be between 128 and 512 bits")
tests := []struct {
@ -562,6 +563,8 @@ func TestExtendedKeyAPI(t *testing.T) {
extKey string
isPrivate bool
parentFP uint32
chainCode []byte
childNum uint32
privKey string
privKeyErr error
pubKey string
@ -572,6 +575,8 @@ func TestExtendedKeyAPI(t *testing.T) {
extKey: "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
isPrivate: true,
parentFP: 0,
chainCode: []byte{135, 61, 255, 129, 192, 47, 82, 86, 35, 253, 31, 229, 22, 126, 172, 58, 85, 160, 73, 222, 61, 49, 75, 180, 46, 226, 39, 255, 237, 55, 213, 8},
childNum: 0,
privKey: "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35",
pubKey: "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
address: "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma",
@ -581,6 +586,8 @@ func TestExtendedKeyAPI(t *testing.T) {
extKey: "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
isPrivate: false,
parentFP: 3203769081,
chainCode: []byte{4, 70, 107, 156, 200, 225, 97, 233, 102, 64, 156, 165, 41, 134, 197, 132, 240, 126, 157, 200, 31, 115, 93, 182, 131, 195, 255, 110, 199, 177, 80, 63},
childNum: 2147483650,
privKeyErr: ErrNotPrivExtKey,
pubKey: "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2",
address: "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x",
@ -610,6 +617,20 @@ func TestExtendedKeyAPI(t *testing.T) {
continue
}
chainCode := key.ChainCode()
if !bytes.Equal(chainCode, test.chainCode) {
t.Errorf("ChainCode #%d (%s): want %v, got %v", i,
test.name, test.chainCode, chainCode)
continue
}
childIndex := key.ChildIndex()
if childIndex != test.childNum {
t.Errorf("ChildIndex #%d (%s): want %d, got %d", i,
test.name, test.childNum, childIndex)
continue
}
serializedKey := key.String()
if serializedKey != test.extKey {
t.Errorf("String #%d (%s): mismatched serialized key "+
@ -830,9 +851,9 @@ func TestErrors(t *testing.T) {
}
// Deriving a hardened child extended key should fail from a public key.
_, err = pubKey.Child(HardenedKeyStart)
_, err = pubKey.Derive(HardenedKeyStart)
if err != ErrDeriveHardFromPublic {
t.Fatalf("Child: mismatched error -- got: %v, want: %v",
t.Fatalf("Derive: mismatched error -- got: %v, want: %v",
err, ErrDeriveHardFromPublic)
}
@ -1052,19 +1073,137 @@ func TestMaximumDepth(t *testing.T) {
t.Fatalf("extendedkey depth %d should match expected value %d",
extKey.Depth(), i)
}
newKey, err := extKey.Child(1)
newKey, err := extKey.Derive(1)
if err != nil {
t.Fatalf("Child: unexpected error: %v", err)
t.Fatalf("Derive: unexpected error: %v", err)
}
extKey = newKey
}
noKey, err := extKey.Child(1)
noKey, err := extKey.Derive(1)
if err != ErrDeriveBeyondMaxDepth {
t.Fatalf("Child: mismatched error: want %v, got %v",
t.Fatalf("Derive: mismatched error: want %v, got %v",
ErrDeriveBeyondMaxDepth, err)
}
if noKey != nil {
t.Fatal("Child: deriving 256th key should not succeed")
t.Fatal("Derive: deriving 256th key should not succeed")
}
}
// TestCloneWithVersion ensures proper conversion between standard and SLIP132
// extended keys.
//
// The following tool was used for generating the tests:
// https://jlopp.github.io/xpub-converter
func TestCloneWithVersion(t *testing.T) {
tests := []struct {
name string
key string
version []byte
want string
wantErr error
}{
{
name: "test xpub to zpub",
key: "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
version: []byte{0x04, 0xb2, 0x47, 0x46},
want: "zpub6jftahH18ngZxUuv6oSniLNrBCSSE1B4EEU59bwTCEt8x6aS6b2mdfLxbS4QS53g85SWWP6wexqeer516433gYpZQoJie2tcMYdJ1SYYYAL",
},
{
name: "test zpub to xpub",
key: "zpub6jftahH18ngZxUuv6oSniLNrBCSSE1B4EEU59bwTCEt8x6aS6b2mdfLxbS4QS53g85SWWP6wexqeer516433gYpZQoJie2tcMYdJ1SYYYAL",
version: []byte{0x04, 0x88, 0xb2, 0x1e},
want: "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
},
{
name: "test xprv to zprv",
key: "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
version: []byte{0x04, 0xb2, 0x43, 0x0c},
want: "zprvAWgYBBk7JR8GjzqSzmunMCS7dAbwpYTCs1YUMDXqduMA5JFHZ3iX5s2UkAR6vBdcCYYa1S5o1fVLrKsrnpCQ4WpUd6aVUWP1bS2Yy5DoaKv",
},
{
name: "test zprv to xprv",
key: "zprvAWgYBBk7JR8GjzqSzmunMCS7dAbwpYTCs1YUMDXqduMA5JFHZ3iX5s2UkAR6vBdcCYYa1S5o1fVLrKsrnpCQ4WpUd6aVUWP1bS2Yy5DoaKv",
version: []byte{0x04, 0x88, 0xad, 0xe4},
want: "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
},
{
name: "test invalid key id",
key: "zprvAWgYBBk7JR8GjzqSzmunMCS7dAbwpYTCs1YUMDXqduMA5JFHZ3iX5s2UkAR6vBdcCYYa1S5o1fVLrKsrnpCQ4WpUd6aVUWP1bS2Yy5DoaKv",
version: []byte{0x4B, 0x1D},
wantErr: chaincfg.ErrUnknownHDKeyID,
},
}
for i, test := range tests {
extKey, err := NewKeyFromString(test.key)
if err != nil {
panic(err) // This is never expected to fail.
}
got, err := extKey.CloneWithVersion(test.version)
if !reflect.DeepEqual(err, test.wantErr) {
t.Errorf("CloneWithVersion #%d (%s): unexpected error -- "+
"want %v, got %v", i, test.name, test.wantErr, err)
continue
}
if test.wantErr == nil {
if k := got.String(); k != test.want {
t.Errorf("CloneWithVersion #%d (%s): "+
"got %s, want %s", i, test.name, k, test.want)
continue
}
}
}
}
// TestLeadingZero ensures that deriving children from keys with a leading zero byte is done according
// to the BIP-32 standard and that the legacy method generates a backwards-compatible result.
func TestLeadingZero(t *testing.T) {
// The 400th seed results in a m/0' public key with a leading zero, allowing us to test
// the desired behavior.
ii := 399
seed := make([]byte, 32)
binary.BigEndian.PutUint32(seed[28:], uint32(ii))
masterKey, err := NewMaster(seed, &chaincfg.MainNetParams)
if err != nil {
t.Fatalf("hdkeychain.NewMaster failed: %v", err)
}
child0, err := masterKey.Derive(0 + HardenedKeyStart)
if err != nil {
t.Fatalf("masterKey.Derive failed: %v", err)
}
if !child0.IsAffectedByIssue172() {
t.Fatal("expected child0 to be affected by issue 172")
}
child1, err := child0.Derive(0 + HardenedKeyStart)
if err != nil {
t.Fatalf("child0.Derive failed: %v", err)
}
if child1.IsAffectedByIssue172() {
t.Fatal("did not expect child1 to be affected by issue 172")
}
child1nonstandard, err := child0.DeriveNonStandard(0 + HardenedKeyStart)
if err != nil {
t.Fatalf("child0.DeriveNonStandard failed: %v", err)
}
// This is the correct result based on BIP32
if hex.EncodeToString(child1.key) != "a9b6b30a5b90b56ed48728c73af1d8a7ef1e9cc372ec21afcc1d9bdf269b0988" {
t.Error("incorrect standard BIP32 derivation")
}
if hex.EncodeToString(child1nonstandard.key) != "ea46d8f58eb863a2d371a938396af8b0babe85c01920f59a8044412e70e837ee" {
t.Error("incorrect lbcutil backwards compatible BIP32-like derivation")
}
if !child0.IsAffectedByIssue172() {
t.Error("child 0 should be affected by issue 172")
}
if child1.IsAffectedByIssue172() {
t.Error("child 1 should not be affected by issue 172")
}
}

View file

@ -1,20 +1,20 @@
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.String 100.00% (18/18)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.Zero 100.00% (9/9)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.pubKeyBytes 100.00% (7/7)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.Neuter 100.00% (6/6)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.ECPrivKey 100.00% (4/4)
github.com/conformal/btcutil/hdkeychain/extendedkey.go zero 100.00% (3/3)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.SetNet 100.00% (3/3)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.Address 100.00% (2/2)
github.com/conformal/btcutil/hdkeychain/extendedkey.go newExtendedKey 100.00% (1/1)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.IsPrivate 100.00% (1/1)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.ParentFingerprint 100.00% (1/1)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.ECPubKey 100.00% (1/1)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.IsForNet 100.00% (1/1)
github.com/conformal/btcutil/hdkeychain/extendedkey.go NewKeyFromString 95.83% (23/24)
github.com/conformal/btcutil/hdkeychain/extendedkey.go ExtendedKey.Child 91.67% (33/36)
github.com/conformal/btcutil/hdkeychain/extendedkey.go NewMaster 91.67% (11/12)
github.com/conformal/btcutil/hdkeychain/extendedkey.go GenerateSeed 85.71% (6/7)
github.com/conformal/btcutil/hdkeychain ----------------------------- 95.59% (130/136)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.String 100.00% (18/18)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.Zero 100.00% (9/9)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.pubKeyBytes 100.00% (7/7)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.Neuter 100.00% (6/6)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.ECPrivKey 100.00% (4/4)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go zero 100.00% (3/3)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.SetNet 100.00% (3/3)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.Address 100.00% (2/2)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go newExtendedKey 100.00% (1/1)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.IsPrivate 100.00% (1/1)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.ParentFingerprint 100.00% (1/1)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.ECPubKey 100.00% (1/1)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.IsForNet 100.00% (1/1)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go NewKeyFromString 95.83% (23/24)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go ExtendedKey.Child 91.67% (33/36)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go NewMaster 91.67% (11/12)
github.com/conformal/lbcutil/hdkeychain/extendedkey.go GenerateSeed 85.71% (6/7)
github.com/conformal/lbcutil/hdkeychain ----------------------------- 95.59% (130/136)

View file

@ -3,18 +3,18 @@
// license that can be found in the LICENSE file.
/*
This test file is part of the btcutil package rather than than the
btcutil_test package so it can bridge access to the internals to properly test
This test file is part of the lbcutil package rather than than the
lbcutil_test package so it can bridge access to the internals to properly test
cases which are either not possible or can't reliably be tested via the public
interface. The functions are only exported while the tests are being run.
*/
package btcutil
package lbcutil
import (
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcutil/base58"
"github.com/btcsuite/btcutil/bech32"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcutil/base58"
"github.com/lbryio/lbcutil/bech32"
"golang.org/x/crypto/ripemd160"
)
@ -85,7 +85,7 @@ func TstAddressPubKey(serializedPubKey []byte, pubKeyFormat PubKeyFormat,
pubKey, _ := btcec.ParsePubKey(serializedPubKey, btcec.S256())
return &AddressPubKey{
pubKeyFormat: pubKeyFormat,
pubKey: (*btcec.PublicKey)(pubKey),
pubKey: pubKey,
pubKeyHashID: netID,
}
}

2
net.go
View file

@ -4,7 +4,7 @@
// +build !appengine
package btcutil
package lbcutil
import (
"net"

View file

@ -4,7 +4,7 @@
// +build appengine
package btcutil
package lbcutil
import (
"net"

View file

@ -5,7 +5,7 @@
package psbt
import (
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
// MinTxVersion is the lowest transaction version that we'll permit.

View file

@ -12,8 +12,8 @@ package psbt
import (
"bytes"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
)
// Extract takes a finalized psbt.Packet and outputs a finalized transaction

View file

@ -12,7 +12,7 @@ package psbt
// multisig and no other custom script.
import (
"github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/txscript"
)
// isFinalized considers this input finalized if it contains at least one of

View file

@ -1,9 +0,0 @@
module github.com/btcsuite/btcutil/psbt
go 1.13
require (
github.com/btcsuite/btcd v0.20.1-beta
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d
github.com/davecgh/go-spew v1.1.1
)

View file

@ -1,36 +0,0 @@
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20191219182022-e17c9730c422 h1:EqnrgSSg0SFWRlEZLExgjtuUR/IPnuQ6qw6nwRda4Uk=
github.com/btcsuite/btcutil v0.0.0-20191219182022-e17c9730c422/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44 h1:9lP3x0pW80sDI6t1UMSLA4to18W7R7imwAI/sWS9S8Q=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -6,8 +6,8 @@ import (
"io"
"sort"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
)
// PInput is a struct encapsulating all the data that can be attached to any
@ -49,19 +49,13 @@ func NewPsbtInput(nonWitnessUtxo *wire.MsgTx,
}
// IsSane returns true only if there are no conflicting values in the Psbt
// PInput. It checks that witness and non-witness utxo entries do not both
// exist, and that witnessScript entries are only added to witness inputs.
// PInput. For segwit v0 no checks are currently implemented.
func (pi *PInput) IsSane() bool {
if pi.NonWitnessUtxo != nil && pi.WitnessUtxo != nil {
return false
}
if pi.WitnessUtxo == nil && pi.WitnessScript != nil {
return false
}
if pi.WitnessUtxo == nil && pi.FinalScriptWitness != nil {
return false
}
// TODO(guggero): Implement sanity checks for segwit v1. For segwit v0
// it is unsafe to only rely on the witness UTXO so we don't check that
// only one is set anymore.
// See https://github.com/bitcoin/bitcoin/pull/19215.
return true
}

View file

@ -5,7 +5,7 @@ import (
"io"
"sort"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
// POutput is a struct encapsulating all the data that can be attached

View file

@ -3,7 +3,7 @@ package psbt
import (
"bytes"
"github.com/btcsuite/btcd/btcec"
"github.com/lbryio/lbcd/btcec"
)
// PartialSig encapsulate a (BTC public key, ECDSA signature)
@ -31,10 +31,7 @@ func (s PartialSigSorter) Less(i, j int) bool {
// Bitcoin context (compressed/uncomp. OK).
func validatePubkey(pubKey []byte) bool {
_, err := btcec.ParsePubKey(pubKey, btcec.S256())
if err != nil {
return false
}
return true
return err == nil
}
// validateSignature checks that the passed byte slice is a valid DER-encoded
@ -42,10 +39,7 @@ func validatePubkey(pubKey []byte) bool {
// validate the signature against any message or public key.
func validateSignature(sig []byte) bool {
_, err := btcec.ParseDERSignature(sig, btcec.S256())
if err != nil {
return false
}
return true
return err == nil
}
// checkValid checks that both the pbukey and sig are valid. See the methods

View file

@ -14,7 +14,7 @@ import (
"io"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
// psbtMagicLength is the length of the magic bytes used to signal the start of

View file

@ -11,9 +11,10 @@ import (
"encoding/hex"
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
"github.com/davecgh/go-spew/spew"
)
@ -161,6 +162,9 @@ func TestReadInvalidPsbt(t *testing.T) {
}
func TestSanityCheck(t *testing.T) {
// TODO(guggero): Remove when checks for segwit v1 are implemented.
t.Skip("Skipping PSBT sanity checks for segwit v0.")
// Test strategy:
// 1. Create an invalid PSBT from a serialization
// Then ensure that the sanity check fails.
@ -613,6 +617,25 @@ var finalizerPsbtData = map[string]string{
"resultb64": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==",
"result": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
"network": "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000",
"twoOfThree": "70736274ff01005e01000000019a5fdb3c36f2168ea34a031857863c63bb776fd8a8a9149efd7341dfaf81c9970000000000ffffffff01e013a8040000000022002001c3a65ccfa5b39e31e6bafa504446200b9c88c58b4f21eb7e18412aff154e3f000000000001012bc817a80400000000220020114c9ab91ea00eb3e81a7aa4d0d8f1bc6bd8761f8f00dbccb38060dc2b9fdd5522020242ecd19afda551d58f496c17e3f51df4488089df4caafac3285ed3b9c590f6a847304402207c6ab50f421c59621323460aaf0f731a1b90ca76eddc635aed40e4d2fc86f97e02201b3f8fe931f1f94fde249e2b5b4dbfaff2f9df66dd97c6b518ffa746a4390bd1012202039f0acfe5a292aafc5331f18f6360a3cc53d645ebf0cc7f0509630b22b5d9f547473044022075329343e01033ebe5a22ea6eecf6361feca58752716bdc2260d7f449360a0810220299740ed32f694acc5f99d80c988bb270a030f63947f775382daf4669b272da0010103040100000001056952210242ecd19afda551d58f496c17e3f51df4488089df4caafac3285ed3b9c590f6a821035a654524d301dd0265c2370225a6837298b8ca2099085568cc61a8491287b63921039f0acfe5a292aafc5331f18f6360a3cc53d645ebf0cc7f0509630b22b5d9f54753ae22060242ecd19afda551d58f496c17e3f51df4488089df4caafac3285ed3b9c590f6a818d5f7375b2c000080000000800000008000000000010000002206035a654524d301dd0265c2370225a6837298b8ca2099085568cc61a8491287b63918e2314cf32c000080000000800000008000000000010000002206039f0acfe5a292aafc5331f18f6360a3cc53d645ebf0cc7f0509630b22b5d9f54718e524a1ce2c000080000000800000008000000000010000000000",
}
func TestFinalize2of3(t *testing.T) {
b, err := hex.DecodeString(finalizerPsbtData["twoOfThree"])
if err != nil {
t.Fatalf("Error decoding hex: %v", err)
}
p, err := NewFromRawBytes(bytes.NewReader(b), false)
if p.IsComplete() {
t.Fatalf("Psbt is complete")
}
err = MaybeFinalizeAll(p)
if err != nil {
t.Fatalf("Error in MaybeFinalizeAll: %v", err)
}
if !p.IsComplete() {
t.Fatalf("Psbt is not complete")
}
}
func TestPsbtExtractor(t *testing.T) {
@ -1317,3 +1340,109 @@ func TestEmptyInputSerialization(t *testing.T) {
t.Fatalf("deserialized transaction not empty")
}
}
// TestWitnessForNonWitnessUtxo makes sure that a packet that only has a non-
// witness UTXO set can still be signed correctly by adding witness data. This
// is to make sure that PSBTs following the CVE-2020-14199 bugfix are not
// rejected. See https://github.com/bitcoin/bitcoin/pull/19215.
func TestWitnessForNonWitnessUtxo(t *testing.T) {
// Our witness UTXO is index 1 of this raw transaction from the test
// vectors.
prevTxRaw, _ := hex.DecodeString("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000")
prevTx := wire.NewMsgTx(2)
err := prevTx.Deserialize(bytes.NewReader(prevTxRaw))
if err != nil {
t.Fatalf("failed to deserialize previous TX: %v", err)
}
// First create a packet that contains one input and one output.
outPkScript, _ := hex.DecodeString(CUTestHexData["scriptPubkey1"])
packet := &Packet{
UnsignedTx: &wire.MsgTx{
Version: 2,
LockTime: 0,
TxIn: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Hash: prevTx.TxHash(),
Index: 1,
},
}},
TxOut: []*wire.TxOut{{
PkScript: outPkScript,
Value: 1.9 * lbcutil.SatoshiPerBitcoin,
}},
},
Inputs: []PInput{{}},
Outputs: []POutput{{}},
}
// Create an updater for the packet. This also performs a sanity check.
updater, err := NewUpdater(packet)
if err != nil {
t.Fatalf("failed to sanity check raw packet: %v", err)
}
// Now add our witness UTXO to the input. But because hardware wallets
// that are patched against CVE-2020-14199 require the full non-witness
// UTXO to be set for all inputs, we do what Core does and add the full
// transaction in the NonWitnessUtxo instead of just the outpoint in
// WitnessUtxo.
err = updater.AddInNonWitnessUtxo(prevTx, 0)
if err != nil {
t.Fatalf("failed to update non-witness UTXO: %v", err)
}
// Then add the redeem scripts and witness scripts.
redeemScript, _ := hex.DecodeString(CUTestHexData["Input2RedeemScript"])
err = updater.AddInRedeemScript(redeemScript, 0)
if err != nil {
t.Fatalf("failed to update redeem script: %v", err)
}
witnessScript, _ := hex.DecodeString(CUTestHexData["Input2WitnessScript"])
err = updater.AddInWitnessScript(witnessScript, 0)
if err != nil {
t.Fatalf("failed to update redeem script: %v", err)
}
// Add the first of the two partial signatures.
sig1, _ := hex.DecodeString("3044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01")
pub1, _ := hex.DecodeString("03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc")
res, err := updater.Sign(0, sig1, pub1, nil, nil)
if err != nil {
t.Fatalf("failed to sign with pubkey 1: %v", err)
}
if res != SignSuccesful {
t.Fatalf("signing was not successful, got result %v", res)
}
// Check that the finalization procedure fails here due to not
// meeting the multisig policy
success, err := MaybeFinalize(packet, 0)
if success {
t.Fatalf("Incorrectly succeeded in finalizing without sigs")
}
if err != ErrUnsupportedScriptType {
t.Fatalf("Got unexpected error type: %v", err)
}
// Add the second partial signature.
sig2, _ := hex.DecodeString("3044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d201")
pub2, _ := hex.DecodeString("023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73")
res, err = updater.Sign(0, sig2, pub2, nil, nil)
if err != nil {
t.Fatalf("failed to sign with pubkey 2: %v", err)
}
if res != SignSuccesful {
t.Fatalf("signing was not successful, got result %v", res)
}
// Finally make sure we can finalize the packet and extract the raw TX.
err = MaybeFinalizeAll(packet)
if err != nil {
t.Fatalf("error finalizing PSBT: %v", err)
}
_, err = Extract(packet)
if err != nil {
t.Fatalf("unable to extract funding TX: %v", err)
}
}

View file

@ -10,7 +10,7 @@ package psbt
// is in the correct state.
import (
"github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/txscript"
)
// SignOutcome is a enum-like value that expresses the outcome of a call to the
@ -142,8 +142,11 @@ func nonWitnessToWitness(p *Packet, inIndex int) error {
outIndex := p.UnsignedTx.TxIn[inIndex].PreviousOutPoint.Index
txout := p.Inputs[inIndex].NonWitnessUtxo.TxOut[outIndex]
// Remove the non-witness first, else sanity check will not pass:
p.Inputs[inIndex].NonWitnessUtxo = nil
// TODO(guggero): For segwit v1, we'll want to remove the NonWitnessUtxo
// from the packet. For segwit v0 it is unsafe to only rely on the
// witness UTXO. See https://github.com/bitcoin/bitcoin/pull/19215.
// p.Inputs[inIndex].NonWitnessUtxo = nil
u := Updater{
Upsbt: p,
}

102
psbt/sort.go Normal file
View file

@ -0,0 +1,102 @@
package psbt
import (
"bytes"
"sort"
"github.com/lbryio/lbcd/chaincfg/chainhash"
)
// InPlaceSort modifies the passed packet's wire TX inputs and outputs to be
// sorted based on BIP 69. The sorting happens in a way that the packet's
// partial inputs and outputs are also modified to match the sorted TxIn and
// TxOuts of the wire transaction.
//
// WARNING: This function must NOT be called with packages that already contain
// (partial) witness data since it will mutate the transaction if it's not
// already sorted. This can cause issues if you mutate a tx in a block, for
// example, which would invalidate the block. It could also cause cached hashes,
// such as in a lbcutil.Tx to become invalidated.
//
// The function should only be used if the caller is creating the transaction or
// is otherwise 100% positive mutating will not cause adverse affects due to
// other dependencies.
func InPlaceSort(packet *Packet) error {
// To make sure we don't run into any nil pointers or array index
// violations during sorting, do a very basic sanity check first.
err := VerifyInputOutputLen(packet, false, false)
if err != nil {
return err
}
sort.Sort(&sortableInputs{p: packet})
sort.Sort(&sortableOutputs{p: packet})
return nil
}
// sortableInputs is a simple wrapper around a packet that implements the
// sort.Interface for sorting the wire and partial inputs of a packet.
type sortableInputs struct {
p *Packet
}
// sortableOutputs is a simple wrapper around a packet that implements the
// sort.Interface for sorting the wire and partial outputs of a packet.
type sortableOutputs struct {
p *Packet
}
// For sortableInputs and sortableOutputs, three functions are needed to make
// them sortable with sort.Sort() -- Len, Less, and Swap.
// Len and Swap are trivial. Less is BIP 69 specific.
func (s *sortableInputs) Len() int { return len(s.p.UnsignedTx.TxIn) }
func (s sortableOutputs) Len() int { return len(s.p.UnsignedTx.TxOut) }
// Swap swaps two inputs.
func (s *sortableInputs) Swap(i, j int) {
tx := s.p.UnsignedTx
tx.TxIn[i], tx.TxIn[j] = tx.TxIn[j], tx.TxIn[i]
s.p.Inputs[i], s.p.Inputs[j] = s.p.Inputs[j], s.p.Inputs[i]
}
// Swap swaps two outputs.
func (s *sortableOutputs) Swap(i, j int) {
tx := s.p.UnsignedTx
tx.TxOut[i], tx.TxOut[j] = tx.TxOut[j], tx.TxOut[i]
s.p.Outputs[i], s.p.Outputs[j] = s.p.Outputs[j], s.p.Outputs[i]
}
// Less is the input comparison function. First sort based on input hash
// (reversed / rpc-style), then index.
func (s *sortableInputs) Less(i, j int) bool {
ins := s.p.UnsignedTx.TxIn
// Input hashes are the same, so compare the index.
ihash := ins[i].PreviousOutPoint.Hash
jhash := ins[j].PreviousOutPoint.Hash
if ihash == jhash {
return ins[i].PreviousOutPoint.Index <
ins[j].PreviousOutPoint.Index
}
// At this point, the hashes are not equal, so reverse them to
// big-endian and return the result of the comparison.
const hashSize = chainhash.HashSize
for b := 0; b < hashSize/2; b++ {
ihash[b], ihash[hashSize-1-b] = ihash[hashSize-1-b], ihash[b]
jhash[b], jhash[hashSize-1-b] = jhash[hashSize-1-b], jhash[b]
}
return bytes.Compare(ihash[:], jhash[:]) == -1
}
// Less is the output comparison function. First sort based on amount (smallest
// first), then PkScript.
func (s *sortableOutputs) Less(i, j int) bool {
outs := s.p.UnsignedTx.TxOut
if outs[i].Value == outs[j].Value {
return bytes.Compare(outs[i].PkScript, outs[j].PkScript) < 0
}
return outs[i].Value < outs[j].Value
}

167
psbt/sort_test.go Normal file
View file

@ -0,0 +1,167 @@
package psbt
import (
"reflect"
"testing"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
)
func TestInPlaceSort(t *testing.T) {
testCases := []struct {
name string
packet *Packet
expectedTxIn []*wire.TxIn
expectedTxOut []*wire.TxOut
expectedPIn []PInput
expectedPOut []POutput
expectErr bool
}{{
name: "packet nil",
packet: nil,
expectErr: true,
}, {
name: "no inputs or outputs",
packet: &Packet{UnsignedTx: &wire.MsgTx{}},
expectErr: false,
}, {
name: "inputs only",
packet: &Packet{
UnsignedTx: &wire.MsgTx{
TxIn: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{99, 88},
Index: 7,
},
}, {
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{77, 88},
Index: 12,
},
}, {
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{77, 88},
Index: 7,
},
}},
},
// Abuse the SighashType as an index to make sure the
// partial inputs are also sorted together with the wire
// inputs.
Inputs: []PInput{{
SighashType: 0,
}, {
SighashType: 1,
}, {
SighashType: 2,
}},
},
expectedTxIn: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{77, 88},
Index: 7,
},
}, {
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{77, 88},
Index: 12,
},
}, {
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{99, 88},
Index: 7,
},
}},
expectedPIn: []PInput{{
SighashType: 2,
}, {
SighashType: 1,
}, {
SighashType: 0,
}},
expectErr: false,
}, {
name: "outputs only",
packet: &Packet{
UnsignedTx: &wire.MsgTx{
TxOut: []*wire.TxOut{{
PkScript: []byte{99, 88},
Value: 7,
}, {
PkScript: []byte{77, 88},
Value: 12,
}, {
PkScript: []byte{77, 88},
Value: 7,
}},
},
// Abuse the RedeemScript as an index to make sure the
// partial inputs are also sorted together with the wire
// inputs.
Outputs: []POutput{{
RedeemScript: []byte{0},
}, {
RedeemScript: []byte{1},
}, {
RedeemScript: []byte{2},
}},
},
expectedTxOut: []*wire.TxOut{{
PkScript: []byte{77, 88},
Value: 7,
}, {
PkScript: []byte{99, 88},
Value: 7,
}, {
PkScript: []byte{77, 88},
Value: 12,
}},
expectedPOut: []POutput{{
RedeemScript: []byte{2},
}, {
RedeemScript: []byte{0},
}, {
RedeemScript: []byte{1},
}},
expectErr: false,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
p := tc.packet
err := InPlaceSort(p)
if (tc.expectErr && err == nil) ||
(!tc.expectErr && err != nil) {
t.Fatalf("got error '%v' but wanted it to be "+
"nil: %v", err, tc.expectErr)
}
// Don't continue on this special test case.
if p == nil {
return
}
tx := p.UnsignedTx
if !reflect.DeepEqual(tx.TxIn, tc.expectedTxIn) {
t.Fatalf("unexpected txin, got %#v wanted %#v",
tx.TxIn, tc.expectedTxIn)
}
if !reflect.DeepEqual(tx.TxOut, tc.expectedTxOut) {
t.Fatalf("unexpected txout, got %#v wanted %#v",
tx.TxOut, tc.expectedTxOut)
}
if !reflect.DeepEqual(p.Inputs, tc.expectedPIn) {
t.Fatalf("unexpected pin, got %#v wanted %#v",
p.Inputs, tc.expectedPIn)
}
if !reflect.DeepEqual(p.Outputs, tc.expectedPOut) {
t.Fatalf("unexpected pout, got %#v wanted %#v",
p.Inputs, tc.expectedPOut)
}
})
}
}

View file

@ -14,9 +14,9 @@ import (
"bytes"
"crypto/sha256"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil"
)
// Updater encapsulates the role 'Updater' as specified in BIP174; it accepts
@ -102,6 +102,11 @@ func (p *Updater) addPartialSignature(inIndex int, sig []byte,
}
}
// Attaching signature without utxo field is not allowed.
if pInput.WitnessUtxo == nil && pInput.NonWitnessUtxo == nil {
return ErrInvalidPsbtFormat
}
// Next, we perform a series of additional sanity checks.
if pInput.NonWitnessUtxo != nil {
if len(p.Upsbt.UnsignedTx.TxIn) < inIndex+1 {
@ -120,7 +125,7 @@ func (p *Updater) addPartialSignature(inIndex int, sig []byte,
if pInput.RedeemScript != nil {
outIndex := p.Upsbt.UnsignedTx.TxIn[inIndex].PreviousOutPoint.Index
scriptPubKey := pInput.NonWitnessUtxo.TxOut[outIndex].PkScript
scriptHash := btcutil.Hash160(pInput.RedeemScript)
scriptHash := lbcutil.Hash160(pInput.RedeemScript)
scriptHashScript, err := txscript.NewScriptBuilder().
AddOp(txscript.OP_HASH160).
@ -136,12 +141,21 @@ func (p *Updater) addPartialSignature(inIndex int, sig []byte,
}
}
} else if pInput.WitnessUtxo != nil {
}
// It could be that we set both the non-witness and witness UTXO fields
// in case it's from a wallet that patched the CVE-2020-14199
// vulnerability. We detect whether the input being spent is actually a
// witness input and then copy it over to the witness UTXO field in the
// signer. Run the witness checks as well, even if we might already have
// checked the script hash. But that should be a negligible performance
// penalty.
if pInput.WitnessUtxo != nil {
scriptPubKey := pInput.WitnessUtxo.PkScript
var script []byte
if pInput.RedeemScript != nil {
scriptHash := btcutil.Hash160(pInput.RedeemScript)
scriptHash := lbcutil.Hash160(pInput.RedeemScript)
scriptHashScript, err := txscript.NewScriptBuilder().
AddOp(txscript.OP_HASH160).
AddData(scriptHash).
@ -181,7 +195,7 @@ func (p *Updater) addPartialSignature(inIndex int, sig []byte,
}
} else {
// Otherwise, this is a p2wkh input.
pubkeyHash := btcutil.Hash160(pubkey)
pubkeyHash := lbcutil.Hash160(pubkey)
pubkeyHashScript, err := txscript.NewScriptBuilder().
AddOp(txscript.OP_0).
AddData(pubkeyHash).
@ -196,10 +210,6 @@ func (p *Updater) addPartialSignature(inIndex int, sig []byte,
return ErrInvalidSignatureForInput
}
}
} else {
// Attaching signature without utxo field is not allowed.
return ErrInvalidPsbtFormat
}
p.Upsbt.Inputs[inIndex].PartialSigs = append(

View file

@ -8,17 +8,18 @@ import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"sort"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
)
// writeTxWitness is a A utility function due to non-exported witness
// WriteTxWitness is a utility function due to non-exported witness
// serialization (writeTxWitness encodes the bitcoin protocol encoding for a
// transaction input's witness into w).
func writeTxWitness(w io.Writer, wit [][]byte) error {
func WriteTxWitness(w io.Writer, wit [][]byte) error {
if err := wire.WriteVarInt(w, 0, uint64(len(wit))); err != nil {
return err
}
@ -39,7 +40,7 @@ func writePKHWitness(sig []byte, pub []byte) ([]byte, error) {
witnessItems = [][]byte{sig, pub}
)
if err := writeTxWitness(&buf, witnessItems); err != nil {
if err := WriteTxWitness(&buf, witnessItems); err != nil {
return nil, err
}
@ -59,14 +60,14 @@ func checkIsMultiSigScript(pubKeys [][]byte, sigs [][]byte,
// Inspect the script to ensure that the number of sigs and pubkeys is
// correct
numSigs, numPubKeys, err := txscript.CalcMultiSigStats(script)
_, numSigs, err := txscript.CalcMultiSigStats(script)
if err != nil {
return false
}
// If the number of sigs provided, doesn't match the number of required
// pubkeys, then we can't proceed as we're not yet final.
if numPubKeys != len(pubKeys) || numSigs != len(sigs) {
if numSigs != len(pubKeys) || numSigs != len(sigs) {
return false
}
@ -173,7 +174,7 @@ func getMultisigScriptWitness(witnessScript []byte, pubKeys [][]byte,
// Now that we have the full witness stack, we'll serialize it in the
// expected format, and return the final bytes.
var buf bytes.Buffer
if err = writeTxWitness(&buf, witnessElements); err != nil {
if err = WriteTxWitness(&buf, witnessElements); err != nil {
return nil, err
}
return buf.Bytes(), nil
@ -214,7 +215,7 @@ func serializeKVPairWithType(w io.Writer, kt uint8, keydata []byte,
}
// The final key to be written is: {type} || {keyData}
serializedKey := append([]byte{byte(kt)}, keydata...)
serializedKey := append([]byte{kt}, keydata...)
return serializeKVpair(w, serializedKey, value)
}
@ -275,3 +276,147 @@ func readTxOut(txout []byte) (*wire.TxOut, error) {
return wire.NewTxOut(int64(valueSer), scriptPubKey), nil
}
// SumUtxoInputValues tries to extract the sum of all inputs specified in the
// UTXO fields of the PSBT. An error is returned if an input is specified that
// does not contain any UTXO information.
func SumUtxoInputValues(packet *Packet) (int64, error) {
// We take the TX ins of the unsigned TX as the truth for how many
// inputs there should be, as the fields in the extra data part of the
// PSBT can be empty.
if len(packet.UnsignedTx.TxIn) != len(packet.Inputs) {
return 0, fmt.Errorf("TX input length doesn't match PSBT " +
"input length")
}
inputSum := int64(0)
for idx, in := range packet.Inputs {
switch {
case in.WitnessUtxo != nil:
// Witness UTXOs only need to reference the TxOut.
inputSum += in.WitnessUtxo.Value
case in.NonWitnessUtxo != nil:
// Non-witness UTXOs reference to the whole transaction
// the UTXO resides in.
utxOuts := in.NonWitnessUtxo.TxOut
txIn := packet.UnsignedTx.TxIn[idx]
// Check that utxOuts actually has enough space to
// contain the previous outpoint's index.
opIdx := txIn.PreviousOutPoint.Index
if opIdx >= uint32(len(utxOuts)) {
return 0, fmt.Errorf("input %d has malformed "+
"TxOut field", idx)
}
inputSum += utxOuts[txIn.PreviousOutPoint.Index].Value
default:
return 0, fmt.Errorf("input %d has no UTXO information",
idx)
}
}
return inputSum, nil
}
// TxOutsEqual returns true if two transaction outputs are equal.
func TxOutsEqual(out1, out2 *wire.TxOut) bool {
if out1 == nil || out2 == nil {
return out1 == out2
}
return out1.Value == out2.Value &&
bytes.Equal(out1.PkScript, out2.PkScript)
}
// VerifyOutputsEqual verifies that the two slices of transaction outputs are
// deep equal to each other. We do the length check and manual loop to provide
// better error messages to the user than just returning "not equal".
func VerifyOutputsEqual(outs1, outs2 []*wire.TxOut) error {
if len(outs1) != len(outs2) {
return fmt.Errorf("number of outputs are different")
}
for idx, out := range outs1 {
// There is a byte slice in the output so we can't use the
// equality operator.
if !TxOutsEqual(out, outs2[idx]) {
return fmt.Errorf("output %d is different", idx)
}
}
return nil
}
// VerifyInputPrevOutpointsEqual verifies that the previous outpoints of the
// two slices of transaction inputs are deep equal to each other. We do the
// length check and manual loop to provide better error messages to the user
// than just returning "not equal".
func VerifyInputPrevOutpointsEqual(ins1, ins2 []*wire.TxIn) error {
if len(ins1) != len(ins2) {
return fmt.Errorf("number of inputs are different")
}
for idx, in := range ins1 {
if in.PreviousOutPoint != ins2[idx].PreviousOutPoint {
return fmt.Errorf("previous outpoint of input %d is "+
"different", idx)
}
}
return nil
}
// VerifyInputOutputLen makes sure a packet is non-nil, contains a non-nil wire
// transaction and that the wire input/output lengths match the partial input/
// output lengths. A caller also can specify if they expect any inputs and/or
// outputs to be contained in the packet.
func VerifyInputOutputLen(packet *Packet, needInputs, needOutputs bool) error {
if packet == nil || packet.UnsignedTx == nil {
return fmt.Errorf("PSBT packet cannot be nil")
}
if len(packet.UnsignedTx.TxIn) != len(packet.Inputs) {
return fmt.Errorf("invalid PSBT, wire inputs don't match " +
"partial inputs")
}
if len(packet.UnsignedTx.TxOut) != len(packet.Outputs) {
return fmt.Errorf("invalid PSBT, wire outputs don't match " +
"partial outputs")
}
if needInputs && len(packet.UnsignedTx.TxIn) == 0 {
return fmt.Errorf("PSBT packet must contain at least one " +
"input")
}
if needOutputs && len(packet.UnsignedTx.TxOut) == 0 {
return fmt.Errorf("PSBT packet must contain at least one " +
"output")
}
return nil
}
// NewFromSignedTx is a utility function to create a packet from an
// already-signed transaction. Returned are: an unsigned transaction
// serialization, a list of scriptSigs, one per input, and a list of witnesses,
// one per input.
func NewFromSignedTx(tx *wire.MsgTx) (*Packet, [][]byte,
[]wire.TxWitness, error) {
scriptSigs := make([][]byte, 0, len(tx.TxIn))
witnesses := make([]wire.TxWitness, 0, len(tx.TxIn))
tx2 := tx.Copy()
// Blank out signature info in inputs
for i, tin := range tx2.TxIn {
tin.SignatureScript = nil
scriptSigs = append(scriptSigs, tx.TxIn[i].SignatureScript)
tin.Witness = nil
witnesses = append(witnesses, tx.TxIn[i].Witness)
}
// Outputs always contain: (value, scriptPubkey) so don't need
// amending. Now tx2 is tx with all signing data stripped out
unsignedPsbt, err := NewFromUnsignedTx(tx2)
if err != nil {
return nil, nil, nil, err
}
return unsignedPsbt, scriptSigs, witnesses, nil
}

370
psbt/utils_test.go Normal file
View file

@ -0,0 +1,370 @@
package psbt
import (
"bytes"
"reflect"
"testing"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
)
func TestSumUtxoInputValues(t *testing.T) {
// Expect sum to fail for packet with non-matching txIn and PInputs.
tx := wire.NewMsgTx(2)
badPacket, err := NewFromUnsignedTx(tx)
if err != nil {
t.Fatalf("could not create packet from TX: %v", err)
}
badPacket.Inputs = append(badPacket.Inputs, PInput{})
_, err = SumUtxoInputValues(badPacket)
if err == nil {
t.Fatalf("expected sum of bad packet to fail")
}
// Expect sum to fail if any inputs don't have UTXO information added.
op := []*wire.OutPoint{{}, {}}
noUtxoInfoPacket, err := New(op, nil, 2, 0, []uint32{0, 0})
if err != nil {
t.Fatalf("could not create new packet: %v", err)
}
_, err = SumUtxoInputValues(noUtxoInfoPacket)
if err == nil {
t.Fatalf("expected sum of missing UTXO info to fail")
}
// Create a packet that is OK and contains both witness and non-witness
// UTXO information.
okPacket, err := New(op, nil, 2, 0, []uint32{0, 0})
if err != nil {
t.Fatalf("could not create new packet: %v", err)
}
okPacket.Inputs[0].WitnessUtxo = &wire.TxOut{Value: 1234}
okPacket.Inputs[1].NonWitnessUtxo = &wire.MsgTx{
TxOut: []*wire.TxOut{{Value: 6543}},
}
sum, err := SumUtxoInputValues(okPacket)
if err != nil {
t.Fatalf("could not sum input: %v", err)
}
if sum != (1234 + 6543) {
t.Fatalf("unexpected sum, got %d wanted %d", sum, 1234+6543)
}
// Create a malformed packet where NonWitnessUtxo.TxOut does not
// contain the index specified by the PreviousOutPoint in the
// packet's Unsigned.TxIn field.
badOp := []*wire.OutPoint{{}, {Index: 500}}
malformedPacket, err := New(badOp, nil, 2, 0, []uint32{0, 0})
if err != nil {
t.Fatalf("could not create malformed packet: %v", err)
}
malformedPacket.Inputs[0].WitnessUtxo = &wire.TxOut{Value: 1234}
malformedPacket.Inputs[1].NonWitnessUtxo = &wire.MsgTx{
TxOut: []*wire.TxOut{{Value: 6543}},
}
_, err = SumUtxoInputValues(malformedPacket)
if err == nil {
t.Fatalf("expected sum of malformed packet to fail")
}
}
func TestTxOutsEqual(t *testing.T) {
testCases := []struct {
name string
out1 *wire.TxOut
out2 *wire.TxOut
expectEqual bool
}{{
name: "both nil",
out1: nil,
out2: nil,
expectEqual: true,
}, {
name: "one nil",
out1: nil,
out2: &wire.TxOut{},
expectEqual: false,
}, {
name: "both empty",
out1: &wire.TxOut{},
out2: &wire.TxOut{},
expectEqual: true,
}, {
name: "one pk script set",
out1: &wire.TxOut{},
out2: &wire.TxOut{
PkScript: []byte("foo"),
},
expectEqual: false,
}, {
name: "both fully set",
out1: &wire.TxOut{
Value: 1234,
PkScript: []byte("bar"),
},
out2: &wire.TxOut{
Value: 1234,
PkScript: []byte("bar"),
},
expectEqual: true,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
result := TxOutsEqual(tc.out1, tc.out2)
if result != tc.expectEqual {
t.Fatalf("unexpected result, got %v wanted %v",
result, tc.expectEqual)
}
})
}
}
func TestVerifyOutputsEqual(t *testing.T) {
testCases := []struct {
name string
outs1 []*wire.TxOut
outs2 []*wire.TxOut
expectErr bool
}{{
name: "both nil",
outs1: nil,
outs2: nil,
expectErr: false,
}, {
name: "one nil",
outs1: nil,
outs2: []*wire.TxOut{{}},
expectErr: true,
}, {
name: "both empty",
outs1: []*wire.TxOut{{}},
outs2: []*wire.TxOut{{}},
expectErr: false,
}, {
name: "one pk script set",
outs1: []*wire.TxOut{{}},
outs2: []*wire.TxOut{{
PkScript: []byte("foo"),
}},
expectErr: true,
}, {
name: "both fully set",
outs1: []*wire.TxOut{{
Value: 1234,
PkScript: []byte("bar"),
}, {}},
outs2: []*wire.TxOut{{
Value: 1234,
PkScript: []byte("bar"),
}, {}},
expectErr: false,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
err := VerifyOutputsEqual(tc.outs1, tc.outs2)
if (tc.expectErr && err == nil) ||
(!tc.expectErr && err != nil) {
t.Fatalf("got error '%v' but wanted it to be "+
"nil: %v", err, tc.expectErr)
}
})
}
}
func TestVerifyInputPrevOutpointsEqual(t *testing.T) {
testCases := []struct {
name string
ins1 []*wire.TxIn
ins2 []*wire.TxIn
expectErr bool
}{{
name: "both nil",
ins1: nil,
ins2: nil,
expectErr: false,
}, {
name: "one nil",
ins1: nil,
ins2: []*wire.TxIn{{}},
expectErr: true,
}, {
name: "both empty",
ins1: []*wire.TxIn{{}},
ins2: []*wire.TxIn{{}},
expectErr: false,
}, {
name: "one previous output set",
ins1: []*wire.TxIn{{}},
ins2: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{11, 22, 33},
Index: 7,
},
}},
expectErr: true,
}, {
name: "both fully set",
ins1: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{11, 22, 33},
Index: 7,
},
}, {}},
ins2: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{11, 22, 33},
Index: 7,
},
}, {}},
expectErr: false,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
err := VerifyInputPrevOutpointsEqual(tc.ins1, tc.ins2)
if (tc.expectErr && err == nil) ||
(!tc.expectErr && err != nil) {
t.Fatalf("got error '%v' but wanted it to be "+
"nil: %v", err, tc.expectErr)
}
})
}
}
func TestVerifyInputOutputLen(t *testing.T) {
testCases := []struct {
name string
packet *Packet
needInputs bool
needOutputs bool
expectErr bool
}{{
name: "packet nil",
packet: nil,
expectErr: true,
}, {
name: "wire tx nil",
packet: &Packet{},
expectErr: true,
}, {
name: "both empty don't need outputs",
packet: &Packet{
UnsignedTx: &wire.MsgTx{},
},
expectErr: false,
}, {
name: "both empty but need outputs",
packet: &Packet{
UnsignedTx: &wire.MsgTx{},
},
needOutputs: true,
expectErr: true,
}, {
name: "both empty but need inputs",
packet: &Packet{
UnsignedTx: &wire.MsgTx{},
},
needInputs: true,
expectErr: true,
}, {
name: "input len mismatch",
packet: &Packet{
UnsignedTx: &wire.MsgTx{
TxIn: []*wire.TxIn{{}},
},
},
needInputs: true,
expectErr: true,
}, {
name: "output len mismatch",
packet: &Packet{
UnsignedTx: &wire.MsgTx{
TxOut: []*wire.TxOut{{}},
},
},
needOutputs: true,
expectErr: true,
}, {
name: "all fully set",
packet: &Packet{
UnsignedTx: &wire.MsgTx{
TxIn: []*wire.TxIn{{}},
TxOut: []*wire.TxOut{{}},
},
Inputs: []PInput{{}},
Outputs: []POutput{{}},
},
needInputs: true,
needOutputs: true,
expectErr: false,
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
err := VerifyInputOutputLen(
tc.packet, tc.needInputs, tc.needOutputs,
)
if (tc.expectErr && err == nil) ||
(!tc.expectErr && err != nil) {
t.Fatalf("got error '%v' but wanted it to be "+
"nil: %v", err, tc.expectErr)
}
})
}
}
func TestNewFromSignedTx(t *testing.T) {
orig := &wire.MsgTx{
TxIn: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{},
SignatureScript: []byte("script"),
Witness: [][]byte{[]byte("witness")},
Sequence: 1234,
}},
TxOut: []*wire.TxOut{{
PkScript: []byte{77, 88},
Value: 99,
}},
}
packet, scripts, witnesses, err := NewFromSignedTx(orig)
if err != nil {
t.Fatalf("could not create packet from signed TX: %v", err)
}
tx := packet.UnsignedTx
expectedTxIn := []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{},
Sequence: 1234,
}}
if !reflect.DeepEqual(tx.TxIn, expectedTxIn) {
t.Fatalf("unexpected txin, got %#v wanted %#v",
tx.TxIn, expectedTxIn)
}
if !reflect.DeepEqual(tx.TxOut, orig.TxOut) {
t.Fatalf("unexpected txout, got %#v wanted %#v",
tx.TxOut, orig.TxOut)
}
if len(scripts) != 1 || !bytes.Equal(scripts[0], []byte("script")) {
t.Fatalf("script not extracted correctly")
}
if len(witnesses) != 1 ||
!bytes.Equal(witnesses[0][0], []byte("witness")) {
t.Fatalf("witness not extracted correctly")
}
}

View file

@ -1,72 +0,0 @@
github.com/conformal/btcutil/base58.go Base58Decode 100.00% (20/20)
github.com/conformal/btcutil/base58.go Base58Encode 100.00% (15/15)
github.com/conformal/btcutil/block.go Block.Tx 100.00% (12/12)
github.com/conformal/btcutil/wif.go WIF.String 100.00% (11/11)
github.com/conformal/btcutil/block.go Block.Transactions 100.00% (11/11)
github.com/conformal/btcutil/amount.go AmountUnit.String 100.00% (8/8)
github.com/conformal/btcutil/tx.go NewTxFromReader 100.00% (6/6)
github.com/conformal/btcutil/block.go NewBlockFromBytes 100.00% (6/6)
github.com/conformal/btcutil/block.go NewBlockFromReader 100.00% (6/6)
github.com/conformal/btcutil/address.go encodeAddress 100.00% (6/6)
github.com/conformal/btcutil/address.go newAddressPubKeyHash 100.00% (5/5)
github.com/conformal/btcutil/address.go newAddressScriptHashFromHash 100.00% (5/5)
github.com/conformal/btcutil/tx.go Tx.Sha 100.00% (5/5)
github.com/conformal/btcutil/block.go Block.Sha 100.00% (5/5)
github.com/conformal/btcutil/amount.go NewAmount 100.00% (5/5)
github.com/conformal/btcutil/amount.go round 100.00% (3/3)
github.com/conformal/btcutil/address.go NewAddressScriptHash 100.00% (2/2)
github.com/conformal/btcutil/amount.go Amount.Format 100.00% (2/2)
github.com/conformal/btcutil/tx.go NewTxFromBytes 100.00% (2/2)
github.com/conformal/btcutil/hash160.go calcHash 100.00% (2/2)
github.com/conformal/btcutil/address.go AddressPubKeyHash.Hash160 100.00% (1/1)
github.com/conformal/btcutil/block.go OutOfRangeError.Error 100.00% (1/1)
github.com/conformal/btcutil/block.go Block.MsgBlock 100.00% (1/1)
github.com/conformal/btcutil/tx.go Tx.MsgTx 100.00% (1/1)
github.com/conformal/btcutil/hash160.go Hash160 100.00% (1/1)
github.com/conformal/btcutil/block.go NewBlockFromBlockAndBytes 100.00% (1/1)
github.com/conformal/btcutil/block.go Block.Height 100.00% (1/1)
github.com/conformal/btcutil/block.go Block.SetHeight 100.00% (1/1)
github.com/conformal/btcutil/block.go NewBlock 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressPubKeyHash.IsForNet 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressPubKey.EncodeAddress 100.00% (1/1)
github.com/conformal/btcutil/address.go NewAddressPubKeyHash 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressPubKeyHash.EncodeAddress 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressPubKeyHash.ScriptAddress 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressPubKeyHash.String 100.00% (1/1)
github.com/conformal/btcutil/address.go NewAddressScriptHashFromHash 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressScriptHash.EncodeAddress 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressScriptHash.ScriptAddress 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressScriptHash.IsForNet 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressScriptHash.String 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressScriptHash.Hash160 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressPubKey.ScriptAddress 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressPubKey.IsForNet 100.00% (1/1)
github.com/conformal/btcutil/address.go AddressPubKey.String 100.00% (1/1)
github.com/conformal/btcutil/tx.go NewTx 100.00% (1/1)
github.com/conformal/btcutil/tx.go Tx.SetIndex 100.00% (1/1)
github.com/conformal/btcutil/amount.go Amount.ToUnit 100.00% (1/1)
github.com/conformal/btcutil/tx.go Tx.Index 100.00% (1/1)
github.com/conformal/btcutil/amount.go Amount.String 100.00% (1/1)
github.com/conformal/btcutil/amount.go Amount.MulF64 100.00% (1/1)
github.com/conformal/btcutil/appdata.go appDataDir 92.00% (23/25)
github.com/conformal/btcutil/block.go Block.TxLoc 88.89% (8/9)
github.com/conformal/btcutil/block.go Block.Bytes 88.89% (8/9)
github.com/conformal/btcutil/address.go NewAddressPubKey 87.50% (7/8)
github.com/conformal/btcutil/address.go DecodeAddress 85.00% (17/20)
github.com/conformal/btcutil/wif.go DecodeWIF 85.00% (17/20)
github.com/conformal/btcutil/address.go AddressPubKey.serialize 80.00% (4/5)
github.com/conformal/btcutil/block.go Block.TxSha 75.00% (3/4)
github.com/conformal/btcutil/wif.go paddedAppend 66.67% (2/3)
github.com/conformal/btcutil/wif.go NewWIF 66.67% (2/3)
github.com/conformal/btcutil/certgen.go NewTLSCertPair 0.00% (0/54)
github.com/conformal/btcutil/wif.go WIF.SerializePubKey 0.00% (0/4)
github.com/conformal/btcutil/address.go AddressPubKey.AddressPubKeyHash 0.00% (0/3)
github.com/conformal/btcutil/address.go AddressPubKey.Format 0.00% (0/1)
github.com/conformal/btcutil/address.go AddressPubKey.PubKey 0.00% (0/1)
github.com/conformal/btcutil/address.go AddressPubKey.SetFormat 0.00% (0/1)
github.com/conformal/btcutil/wif.go WIF.IsForNet 0.00% (0/1)
github.com/conformal/btcutil/appdata.go AppDataDir 0.00% (0/1)
github.com/conformal/btcutil/net.go interfaceAddrs 0.00% (0/1)
github.com/conformal/btcutil ------------------------------- 75.88% (258/340)

8
tx.go
View file

@ -2,14 +2,14 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
import (
"bytes"
"io"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
)
// TxIndexUnknown is the value returned for a transaction index that is unknown.
@ -70,7 +70,7 @@ func (t *Tx) WitnessHash() *chainhash.Hash {
// HasWitness on the underlying wire.MsgTx, however it caches the result so
// subsequent calls are more efficient.
func (t *Tx) HasWitness() bool {
if t.txHashWitness != nil {
if t.txHasWitness != nil {
return *t.txHasWitness
}

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil_test
package lbcutil_test
import (
"bytes"
@ -10,15 +10,15 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcutil"
"github.com/davecgh/go-spew/spew"
)
// TestTx tests the API for Tx.
func TestTx(t *testing.T) {
testTx := Block100000.Transactions[0]
tx := btcutil.NewTx(testTx)
tx := lbcutil.NewTx(testTx)
// Ensure we get the same data back out.
if msgTx := tx.MsgTx(); !reflect.DeepEqual(msgTx, testTx) {
@ -63,7 +63,7 @@ func TestNewTxFromBytes(t *testing.T) {
testTxBytes := testTxBuf.Bytes()
// Create a new transaction from the serialized bytes.
tx, err := btcutil.NewTxFromBytes(testTxBytes)
tx, err := lbcutil.NewTxFromBytes(testTxBytes)
if err != nil {
t.Errorf("NewTxFromBytes: %v", err)
return
@ -89,9 +89,48 @@ func TestTxErrors(t *testing.T) {
// Truncate the transaction byte buffer to force errors.
shortBytes := testTxBytes[:4]
_, err = btcutil.NewTxFromBytes(shortBytes)
_, err = lbcutil.NewTxFromBytes(shortBytes)
if err != io.EOF {
t.Errorf("NewTxFromBytes: did not get expected error - "+
"got %v, want %v", err, io.EOF)
}
}
// TestTxHasWitness tests the HasWitness() method.
func TestTxHasWitness(t *testing.T) {
msgTx := Block100000.Transactions[0] // contains witness data
tx := lbcutil.NewTx(msgTx)
tx.WitnessHash() // Populate the witness hash cache
tx.HasWitness() // Should not fail (see btcsuite/btcd#1543)
if !tx.HasWitness() {
t.Errorf("HasWitness: got false, want true")
}
for _, msgTxWithoutWitness := range Block100000.Transactions[1:] {
txWithoutWitness := lbcutil.NewTx(msgTxWithoutWitness)
if txWithoutWitness.HasWitness() {
t.Errorf("HasWitness: got false, want true")
}
}
}
// TestTxWitnessHash tests the WitnessHash() method.
func TestTxWitnessHash(t *testing.T) {
msgTx := Block100000.Transactions[0] // contains witness data
tx := lbcutil.NewTx(msgTx)
if tx.WitnessHash().IsEqual(tx.Hash()) {
t.Errorf("WitnessHash: witness hash and tx id must NOT be same - "+
"got %v, want %v", tx.WitnessHash(), tx.Hash())
}
for _, msgTxWithoutWitness := range Block100000.Transactions[1:] {
txWithoutWitness := lbcutil.NewTx(msgTxWithoutWitness)
if !txWithoutWitness.WitnessHash().IsEqual(txWithoutWitness.Hash()) {
t.Errorf("WitnessHash: witness hash and tx id must be same - "+
"got %v, want %v", txWithoutWitness.WitnessHash(), txWithoutWitness.Hash())
}
}
}

View file

@ -1,9 +1,7 @@
txsort
======
[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcutil/txsort)
Package txsort provides the transaction sorting according to [BIP 69](https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki).
@ -17,15 +15,4 @@ then on the index as a tie breaker. The order for outputs is defined as first
sorting on the amount and then on the raw public key script bytes as a tie
breaker.
A comprehensive suite of tests is provided to ensure proper functionality.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcutil/txsort
```
## License
Package txsort is licensed under the [copyfree](http://copyfree.org) ISC
License.
A comprehensive suite of tests is provided to ensure proper functionality.

View file

@ -11,8 +11,8 @@ import (
"bytes"
"sort"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
)
// InPlaceSort modifies the passed transaction inputs and outputs to be sorted
@ -21,7 +21,7 @@ import (
// WARNING: This function must NOT be called with published transactions since
// it will mutate the transaction if it's not already sorted. This can cause
// issues if you mutate a tx in a block, for example, which would invalidate the
// block. It could also cause cached hashes, such as in a btcutil.Tx to become
// block. It could also cause cached hashes, such as in a lbcutil.Tx to become
// invalidated.
//
// The function should only be used if the caller is creating the transaction or

View file

@ -11,8 +11,8 @@ import (
"path/filepath"
"testing"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil/txsort"
"github.com/lbryio/lbcd/wire"
"github.com/lbryio/lbcutil/txsort"
)
// TestSort ensures the transaction sorting works according to the BIP.

10
wif.go
View file

@ -2,16 +2,16 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
package lbcutil
import (
"bytes"
"errors"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil/base58"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcutil/base58"
)
// ErrMalformedPrivateKey describes an error where a WIF-encoded private

View file

@ -1,71 +1,156 @@
// Copyright (c) 2013, 2014 The btcsuite developers
// Copyright (c) 2013 - 2020 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil_test
package lbcutil_test
import (
"bytes"
"encoding/hex"
"testing"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
. "github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcd/chaincfg"
. "github.com/lbryio/lbcutil"
)
func TestEncodeDecodeWIF(t *testing.T) {
priv1, _ := btcec.PrivKeyFromBytes(btcec.S256(), []byte{
0x0c, 0x28, 0xfc, 0xa3, 0x86, 0xc7, 0xa2, 0x27,
0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d})
priv2, _ := btcec.PrivKeyFromBytes(btcec.S256(), []byte{
0xdd, 0xa3, 0x5a, 0x14, 0x88, 0xfb, 0x97, 0xb6,
0xeb, 0x3f, 0xe6, 0xe9, 0xef, 0x2a, 0x25, 0x81,
0x4e, 0x39, 0x6f, 0xb5, 0xdc, 0x29, 0x5f, 0xe9,
0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98})
wif1, err := NewWIF(priv1, &chaincfg.MainNetParams, false)
if err != nil {
t.Fatal(err)
}
wif2, err := NewWIF(priv2, &chaincfg.TestNet3Params, true)
if err != nil {
t.Fatal(err)
}
tests := []struct {
wif *WIF
encoded string
validEncodeCases := []struct {
privateKey []byte // input
net *chaincfg.Params // input
compress bool // input
wif string // output
publicKey []byte // output
name string // name of subtest
}{
{
wif1,
"5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ",
privateKey: []byte{
0x0c, 0x28, 0xfc, 0xa3, 0x86, 0xc7, 0xa2, 0x27,
0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d},
net: &chaincfg.MainNetParams,
compress: false,
wif: "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ",
publicKey: []byte{
0x04, 0xd0, 0xde, 0x0a, 0xae, 0xae, 0xfa, 0xd0,
0x2b, 0x8b, 0xdc, 0x8a, 0x01, 0xa1, 0xb8, 0xb1,
0x1c, 0x69, 0x6b, 0xd3, 0xd6, 0x6a, 0x2c, 0x5f,
0x10, 0x78, 0x0d, 0x95, 0xb7, 0xdf, 0x42, 0x64,
0x5c, 0xd8, 0x52, 0x28, 0xa6, 0xfb, 0x29, 0x94,
0x0e, 0x85, 0x8e, 0x7e, 0x55, 0x84, 0x2a, 0xe2,
0xbd, 0x11, 0x5d, 0x1e, 0xd7, 0xcc, 0x0e, 0x82,
0xd9, 0x34, 0xe9, 0x29, 0xc9, 0x76, 0x48, 0xcb,
0x0a},
name: "encodeValidUncompressedMainNetWif",
},
{
wif2,
"cV1Y7ARUr9Yx7BR55nTdnR7ZXNJphZtCCMBTEZBJe1hXt2kB684q",
privateKey: []byte{
0xdd, 0xa3, 0x5a, 0x14, 0x88, 0xfb, 0x97, 0xb6,
0xeb, 0x3f, 0xe6, 0xe9, 0xef, 0x2a, 0x25, 0x81,
0x4e, 0x39, 0x6f, 0xb5, 0xdc, 0x29, 0x5f, 0xe9,
0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98},
net: &chaincfg.TestNet3Params,
compress: true,
wif: "cV1Y7ARUr9Yx7BR55nTdnR7ZXNJphZtCCMBTEZBJe1hXt2kB684q",
publicKey: []byte{
0x02, 0xee, 0xc2, 0x54, 0x06, 0x61, 0xb0, 0xc3,
0x9d, 0x27, 0x15, 0x70, 0x74, 0x24, 0x13, 0xbd,
0x02, 0x93, 0x2d, 0xd0, 0x09, 0x34, 0x93, 0xfd,
0x0b, 0xec, 0xed, 0x0b, 0x7f, 0x93, 0xad, 0xde,
0xc4},
name: "encodeValidCompressedTestNet3Wif",
},
}
for _, test := range tests {
// Test that encoding the WIF structure matches the expected string.
s := test.wif.String()
if s != test.encoded {
t.Errorf("TestEncodeDecodePrivateKey failed: want '%s', got '%s'",
test.encoded, s)
continue
}
for _, validCase := range validEncodeCases {
t.Run(validCase.name, func(t *testing.T) {
priv, _ := btcec.PrivKeyFromBytes(btcec.S256(), validCase.privateKey)
wif, err := NewWIF(priv, validCase.net, validCase.compress)
if err != nil {
t.Fatalf("NewWIF failed: expected no error, got '%v'", err)
}
// Test that decoding the expected string results in the original WIF
// structure.
w, err := DecodeWIF(test.encoded)
if err != nil {
t.Error(err)
continue
}
if got := w.String(); got != test.encoded {
t.Errorf("NewWIF failed: want '%v', got '%v'", test.wif, got)
}
if !wif.IsForNet(validCase.net) {
t.Fatal("IsForNet failed: got 'false', want 'true'")
}
if gotPubKey := wif.SerializePubKey(); !bytes.Equal(gotPubKey, validCase.publicKey) {
t.Fatalf("SerializePubKey failed: got '%s', want '%s'",
hex.EncodeToString(gotPubKey), hex.EncodeToString(validCase.publicKey))
}
// Test that encoding the WIF structure matches the expected string.
got := wif.String()
if got != validCase.wif {
t.Fatalf("NewWIF failed: want '%s', got '%s'",
validCase.wif, got)
}
// Test that decoding the expected string results in the original WIF
// structure.
decodedWif, err := DecodeWIF(got)
if err != nil {
t.Fatalf("DecodeWIF failed: expected no error, got '%v'", err)
}
if decodedWifString := decodedWif.String(); decodedWifString != validCase.wif {
t.Fatalf("NewWIF failed: want '%v', got '%v'", validCase.wif, decodedWifString)
}
})
}
invalidDecodeCases := []struct {
name string
wif string
err error
}{
{
name: "decodeInvalidLengthWif",
wif: "deadbeef",
err: ErrMalformedPrivateKey,
},
{
name: "decodeInvalidCompressMagicWif",
wif: "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sfZr2ym",
err: ErrMalformedPrivateKey,
},
{
name: "decodeInvalidChecksumWif",
wif: "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTj",
err: ErrChecksumMismatch,
},
}
for _, invalidCase := range invalidDecodeCases {
t.Run(invalidCase.name, func(t *testing.T) {
decodedWif, err := DecodeWIF(invalidCase.wif)
if decodedWif != nil {
t.Fatalf("DecodeWIF: unexpectedly succeeded - got '%v', want '%v'",
decodedWif, nil)
}
if err != invalidCase.err {
t.Fatalf("DecodeWIF: expected error '%v', got '%v'",
invalidCase.err, err)
}
})
}
t.Run("encodeInvalidNetworkWif", func(t *testing.T) {
privateKey := []byte{
0x0c, 0x28, 0xfc, 0xa3, 0x86, 0xc7, 0xa2, 0x27,
0x60, 0x0b, 0x2f, 0xe5, 0x0b, 0x7c, 0xae, 0x11,
0xec, 0x86, 0xd3, 0xbf, 0x1f, 0xbe, 0x47, 0x1b,
0xe8, 0x98, 0x27, 0xe1, 0x9d, 0x72, 0xaa, 0x1d}
priv, _ := btcec.PrivKeyFromBytes(btcec.S256(), privateKey)
wif, err := NewWIF(priv, nil, true)
if wif != nil {
t.Fatalf("NewWIF: unexpectedly succeeded - got '%v', want '%v'",
wif, nil)
}
if err == nil || err.Error() != "no network" {
t.Fatalf("NewWIF: expected error 'no network', got '%v'", err)
}
})
}