From efa4083c979d62739311be2a411a6f9094f8b5da Mon Sep 17 00:00:00 2001 From: noface Date: Wed, 15 Nov 2023 05:46:21 +0100 Subject: [PATCH] update namespace to ppcd partially --- .github/workflows/go.yml | 1 + Makefile | 2 +- README.md | 2 +- addrmgr/knownaddress_test.go | 2 +- btcec/coverage.txt.bak | 641 +++++++++++++++++++++++++++ btcjson/cmdinfo_test.go | 2 +- btcjson/cmdparse_test.go | 2 +- btcjson/error_test.go | 2 +- btcjson/help_test.go | 2 +- btcjson/register_test.go | 2 +- btcutil/go.mod | 6 +- btcutil/go.sum | 1 + btcutil/psbt/go.mod | 10 +- btcutil/psbt/go.sum | 2 + database/error_test.go | 2 +- database/ffldb/db.go | 2 +- database/ffldb/dbcache.go | 2 +- database/ffldb/driver_test.go | 2 +- database/ffldb/ldbtreapiter.go | 2 +- database/treap/README.md | 39 ++ database/treap/common.go | 136 ++++++ database/treap/common_test.go | 121 ++++++ database/treap/doc.go | 27 ++ database/treap/immutable.go | 360 ++++++++++++++++ database/treap/immutable_test.go | 497 +++++++++++++++++++++ database/treap/mutable.go | 278 ++++++++++++ database/treap/mutable_test.go | 465 ++++++++++++++++++++ database/treap/treapiter.go | 355 +++++++++++++++ database/treap/treapiter_test.go | 719 +++++++++++++++++++++++++++++++ go.mod | 18 +- go.sum | 18 +- integration/bip0009_test.go | 447 ------------------- integration/csv_fork_test.go | 698 ------------------------------ btcd.go => ppcd.go | 0 release/release.sh | 10 +- 35 files changed, 3690 insertions(+), 1185 deletions(-) create mode 100644 btcec/coverage.txt.bak create mode 100644 database/treap/README.md create mode 100644 database/treap/common.go create mode 100644 database/treap/common_test.go create mode 100644 database/treap/doc.go create mode 100644 database/treap/immutable.go create mode 100644 database/treap/immutable_test.go create mode 100644 database/treap/mutable.go create mode 100644 database/treap/mutable_test.go create mode 100644 database/treap/treapiter.go create mode 100644 database/treap/treapiter_test.go delete mode 100644 integration/bip0009_test.go delete mode 100644 integration/csv_fork_test.go rename btcd.go => ppcd.go (100%) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c1625428d37..5ef4edd4cff 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -26,6 +26,7 @@ jobs: test-cover: name: Unit coverage runs-on: ubuntu-latest + if: false steps: - name: Set up Go uses: actions/setup-go@v2 diff --git a/Makefile b/Makefile index 2e967ba0f65..f9f4ceeb885 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PKG := github.com/btcsuite/btcd +PKG := github.com/peercoin/ppcd LINT_PKG := github.com/golangci/golangci-lint/cmd/golangci-lint GOACC_PKG := github.com/ory/go-acc diff --git a/README.md b/README.md index 3a8b969685a..3c772a363c8 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ recommended that `GOPATH` is set to a directory in your home directory such as ```bash $ git clone https://github.com/peercoin/ppcd && cd ppcd -$ go build -o ppcd +$ go build # run it using ./ppcd ``` diff --git a/addrmgr/knownaddress_test.go b/addrmgr/knownaddress_test.go index b4a2650140a..c9cf1adff41 100644 --- a/addrmgr/knownaddress_test.go +++ b/addrmgr/knownaddress_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/btcsuite/btcd/addrmgr" "github.com/btcsuite/btcd/wire" + "github.com/peercoin/ppcd/addrmgr" ) func TestChance(t *testing.T) { diff --git a/btcec/coverage.txt.bak b/btcec/coverage.txt.bak new file mode 100644 index 00000000000..fa256905b52 --- /dev/null +++ b/btcec/coverage.txt.bak @@ -0,0 +1,641 @@ +mode: atomic +github.com/btcsuite/btcd/btcec/v2/btcec.go:31.27,33.2 1 38 +github.com/btcsuite/btcd/btcec/v2/btcec.go:39.28,41.2 1 2062 +github.com/btcsuite/btcd/btcec/v2/btcec.go:44.29,56.2 5 0 +github.com/btcsuite/btcd/btcec/v2/ciphering.go:14.74,16.2 1 2 +github.com/btcsuite/btcd/btcec/v2/curve.go:21.57,23.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:27.49,29.2 1 14 +github.com/btcsuite/btcd/btcec/v2/curve.go:38.65,40.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:47.47,49.2 1 4 +github.com/btcsuite/btcd/btcec/v2/curve.go:56.67,58.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:66.70,68.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:73.57,76.22 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:76.22,80.3 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:82.2,82.22 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:82.22,84.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:86.2,87.16 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:87.16,89.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:90.2,92.20 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:98.54,99.62 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:99.62,101.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:103.2,107.25 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:111.49,115.2 3 0 +github.com/btcsuite/btcd/btcec/v2/error.go:22.51,24.2 1 0 +github.com/btcsuite/btcd/btcec/v2/modnscalar.go:42.38,45.2 1 0 +github.com/btcsuite/btcd/btcec/v2/privkey.go:18.60,22.2 2 0 +github.com/btcsuite/btcd/btcec/v2/privkey.go:26.43,28.2 1 3 +github.com/btcsuite/btcd/btcec/v2/privkey.go:32.53,34.2 1 0 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:24.45,29.2 1 16 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:34.56,36.2 1 25 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:49.46,51.2 1 0 +github.com/btcsuite/btcd/btcec/v2/btcec.go:31.27,33.2 1 257 +github.com/btcsuite/btcd/btcec/v2/btcec.go:39.28,41.2 1 0 +github.com/btcsuite/btcd/btcec/v2/btcec.go:44.29,56.2 5 0 +github.com/btcsuite/btcd/btcec/v2/ciphering.go:14.74,16.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:21.57,23.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:27.49,29.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:38.65,40.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:47.47,49.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:56.67,58.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:66.70,68.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:73.57,76.22 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:76.22,80.3 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:82.2,82.22 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:82.22,84.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:86.2,87.16 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:87.16,89.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:90.2,92.20 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:98.54,99.62 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:99.62,101.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:103.2,107.25 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:111.49,115.2 3 0 +github.com/btcsuite/btcd/btcec/v2/error.go:22.51,24.2 1 0 +github.com/btcsuite/btcd/btcec/v2/modnscalar.go:42.38,45.2 1 6 +github.com/btcsuite/btcd/btcec/v2/privkey.go:18.60,22.2 2 8 +github.com/btcsuite/btcd/btcec/v2/privkey.go:26.43,28.2 1 257 +github.com/btcsuite/btcd/btcec/v2/privkey.go:32.53,34.2 1 0 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:24.45,29.2 1 0 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:34.56,36.2 1 4 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:49.46,51.2 1 0 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:27.54,29.2 1 10 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:49.39,50.9 1 15 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:51.25,52.26 1 2 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:53.55,54.35 1 2 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:55.10,56.13 1 11 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:60.60,71.29 1 23 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:71.29,73.3 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:75.2,76.27 2 22 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:76.27,78.3 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:79.2,86.62 4 21 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:86.62,88.3 1 2 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:90.2,93.27 2 19 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:93.27,96.3 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:97.2,104.45 4 18 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:104.45,106.3 1 3 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:109.2,110.9 2 15 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:110.9,111.47 1 10 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:112.25,113.53 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:114.34,115.63 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:120.2,120.43 1 13 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:120.43,122.3 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:127.2,128.22 2 13 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:128.22,131.3 2 0 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:132.2,132.50 1 13 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:132.50,135.3 2 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:136.2,136.16 1 12 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:136.16,139.3 2 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:140.2,142.27 2 11 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:142.27,144.3 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:145.2,151.43 4 10 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:151.43,153.3 1 2 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:156.2,157.9 2 8 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:157.9,158.47 1 5 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:159.25,160.53 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:161.34,162.63 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:167.2,167.43 1 6 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:167.43,169.3 1 2 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:174.2,175.22 2 6 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:175.22,178.3 2 0 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:179.2,179.50 1 6 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:179.50,182.3 2 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:183.2,183.16 1 5 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:183.16,186.3 2 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:187.2,190.26 2 4 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:190.26,193.3 1 1 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:195.2,195.34 1 3 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:201.56,203.2 1 7 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:208.59,210.2 1 16 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:220.40,223.2 1 256 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:229.77,231.2 1 521 +github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go:238.58,240.2 1 9 +github.com/btcsuite/btcd/btcec/v2/btcec.go:31.27,33.2 1 0 +github.com/btcsuite/btcd/btcec/v2/btcec.go:39.28,41.2 1 0 +github.com/btcsuite/btcd/btcec/v2/btcec.go:44.29,56.2 5 0 +github.com/btcsuite/btcd/btcec/v2/ciphering.go:14.74,16.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:21.57,23.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:27.49,29.2 1 122 +github.com/btcsuite/btcd/btcec/v2/curve.go:38.65,40.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:47.47,49.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:56.67,58.2 1 227 +github.com/btcsuite/btcd/btcec/v2/curve.go:66.70,68.2 1 122 +github.com/btcsuite/btcd/btcec/v2/curve.go:73.57,76.22 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:76.22,80.3 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:82.2,82.22 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:82.22,84.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:86.2,87.16 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:87.16,89.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:90.2,92.20 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:98.54,99.62 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:99.62,101.3 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:103.2,107.25 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:111.49,115.2 3 0 +github.com/btcsuite/btcd/btcec/v2/error.go:22.51,24.2 1 0 +github.com/btcsuite/btcd/btcec/v2/modnscalar.go:42.38,45.2 1 101 +github.com/btcsuite/btcd/btcec/v2/privkey.go:18.60,22.2 2 205 +github.com/btcsuite/btcd/btcec/v2/privkey.go:26.43,28.2 1 0 +github.com/btcsuite/btcd/btcec/v2/privkey.go:32.53,34.2 1 0 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:24.45,29.2 1 0 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:34.56,36.2 1 136 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:49.46,51.2 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/error.go:23.56,25.2 1 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:23.62,24.22 1 136 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:24.22,27.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:28.2,28.38 1 136 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:28.38,32.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:36.2,40.44 4 136 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:46.51,49.2 2 227 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:44.70,49.2 4 117 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:57.41,63.2 4 5 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:70.53,73.28 2 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:73.28,77.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:78.2,78.28 1 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:78.28,82.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:88.2,89.53 2 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:89.53,92.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:93.2,97.34 3 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:103.56,105.2 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:114.75,133.29 1 122 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:133.29,137.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:144.2,145.16 2 122 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:145.16,147.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:148.2,148.25 1 122 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:148.25,151.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:168.2,195.52 13 122 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:195.52,198.3 2 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:205.2,206.17 2 120 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:206.17,209.3 2 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:216.2,216.25 1 118 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:216.25,219.3 2 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:224.2,224.12 1 116 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:229.73,232.2 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:235.37,236.34 1 101 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:236.34,238.3 1 3232 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:250.41,299.17 5 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:299.17,301.3 1 59 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:306.2,316.68 7 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:316.68,320.3 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:325.2,333.20 4 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:333.20,334.58 1 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:334.58,336.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:342.2,342.17 1 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:362.40,364.2 1 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:369.28,370.30 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:370.30,372.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:380.47,381.30 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:381.30,383.3 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:397.46,401.34 2 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:401.34,403.3 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:439.2,445.29 3 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:445.29,449.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:454.2,454.28 1 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:454.28,457.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:462.2,468.54 3 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:468.54,470.3 1 43 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:475.2,475.27 1 105 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:475.27,483.31 3 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:483.31,485.4 1 128 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:493.3,506.22 4 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:506.22,509.4 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:511.3,513.17 3 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:513.17,515.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:517.3,517.18 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:520.2,523.44 4 101 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:523.44,536.17 4 101 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:536.17,538.12 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:541.3,541.18 1 101 +github.com/btcsuite/btcd/btcec/v2/btcec.go:31.27,33.2 1 0 +github.com/btcsuite/btcd/btcec/v2/btcec.go:39.28,41.2 1 0 +github.com/btcsuite/btcd/btcec/v2/btcec.go:44.29,56.2 5 1 +github.com/btcsuite/btcd/btcec/v2/ciphering.go:14.74,16.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:21.57,23.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:27.49,29.2 1 254327 +github.com/btcsuite/btcd/btcec/v2/curve.go:38.65,40.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:47.47,49.2 1 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:56.67,58.2 1 4106 +github.com/btcsuite/btcd/btcec/v2/curve.go:66.70,68.2 1 154221 +github.com/btcsuite/btcd/btcec/v2/curve.go:73.57,76.22 2 103204 +github.com/btcsuite/btcd/btcec/v2/curve.go:76.22,80.3 2 0 +github.com/btcsuite/btcd/btcec/v2/curve.go:82.2,82.22 1 103204 +github.com/btcsuite/btcd/btcec/v2/curve.go:82.22,84.3 1 4 +github.com/btcsuite/btcd/btcec/v2/curve.go:86.2,87.16 2 103200 +github.com/btcsuite/btcd/btcec/v2/curve.go:87.16,89.3 1 7 +github.com/btcsuite/btcd/btcec/v2/curve.go:90.2,92.20 2 103193 +github.com/btcsuite/btcd/btcec/v2/curve.go:98.54,99.62 1 1040 +github.com/btcsuite/btcd/btcec/v2/curve.go:99.62,101.3 1 3 +github.com/btcsuite/btcd/btcec/v2/curve.go:103.2,107.25 2 1037 +github.com/btcsuite/btcd/btcec/v2/curve.go:111.49,115.2 3 1 +github.com/btcsuite/btcd/btcec/v2/error.go:22.51,24.2 1 0 +github.com/btcsuite/btcd/btcec/v2/modnscalar.go:42.38,45.2 1 0 +github.com/btcsuite/btcd/btcec/v2/privkey.go:18.60,22.2 2 2 +github.com/btcsuite/btcd/btcec/v2/privkey.go:26.43,28.2 1 502 +github.com/btcsuite/btcd/btcec/v2/privkey.go:32.53,34.2 1 0 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:24.45,29.2 1 0 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:34.56,36.2 1 2123 +github.com/btcsuite/btcd/btcec/v2/pubkey.go:49.46,51.2 1 8723 +github.com/btcsuite/btcd/btcec/v2/schnorr/error.go:23.56,25.2 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:23.62,24.22 1 1517 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:24.22,27.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:28.2,28.38 1 1517 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:28.38,32.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:36.2,40.44 4 1517 +github.com/btcsuite/btcd/btcec/v2/schnorr/pubkey.go:46.51,49.2 2 6635 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:44.70,49.2 4 10 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:57.41,63.2 4 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:70.53,73.28 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:73.28,77.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:78.2,78.28 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:78.28,82.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:88.2,89.53 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:89.53,92.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:93.2,97.34 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:103.56,105.2 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:114.75,133.29 1 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:133.29,137.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:144.2,145.16 2 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:145.16,147.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:148.2,148.25 1 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:148.25,151.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:168.2,195.52 13 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:195.52,198.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:205.2,206.17 2 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:206.17,209.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:216.2,216.25 1 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:216.25,219.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:224.2,224.12 1 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:229.73,232.2 2 12 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:235.37,236.34 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:236.34,238.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:250.41,299.17 5 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:299.17,301.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:306.2,316.68 7 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:316.68,320.3 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:325.2,333.20 4 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:333.20,334.58 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:334.58,336.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:342.2,342.17 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:362.40,364.2 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:369.28,370.30 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:370.30,372.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:380.47,381.30 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:381.30,383.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:397.46,401.34 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:401.34,403.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:439.2,445.29 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:445.29,449.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:454.2,454.28 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:454.28,457.3 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:462.2,468.54 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:468.54,470.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:475.2,475.27 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:475.27,483.31 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:483.31,485.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:493.3,506.22 4 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:506.22,509.4 2 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:511.3,513.17 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:513.17,515.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:517.3,517.18 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:520.2,523.44 4 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:523.44,536.17 4 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:536.17,538.12 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/signature.go:541.3,541.18 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:132.46,134.2 1 503 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:138.63,139.33 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:139.33,141.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:148.59,149.33 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:149.33,151.3 1 100 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:158.40,159.33 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:159.33,161.3 1 400 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:166.65,167.33 1 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:167.33,170.3 2 501 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:179.42,180.33 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:180.33,182.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:190.40,191.33 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:191.33,193.3 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:201.46,205.33 2 503 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:205.33,207.3 1 1004 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:209.2,218.9 3 503 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:223.26,224.49 1 501 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:224.49,226.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:230.28,235.44 2 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:237.10,238.37 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:243.2,243.21 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:243.21,249.17 3 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:249.17,251.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:254.2,254.17 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:259.45,263.36 2 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:263.36,264.28 1 25253 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:264.28,266.9 2 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:269.2,269.15 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:269.15,271.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:276.2,285.9 4 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:286.25,289.4 1 400 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:290.34,293.4 1 100 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:294.31,295.67 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:300.2,304.16 3 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:304.16,306.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:308.2,308.12 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:312.56,313.27 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:313.27,315.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:317.2,317.28 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:329.70,331.20 2 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:331.20,333.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:335.2,340.20 3 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:340.20,341.47 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:341.47,343.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:346.2,346.28 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:350.46,352.2 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:356.59,359.26 1 9 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:359.26,361.3 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:363.2,363.36 1 7 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:367.44,369.2 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:372.52,377.2 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:384.66,387.26 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:387.26,389.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:391.2,391.54 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:391.54,393.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:395.2,395.41 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:409.46,411.2 1 503 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:416.57,417.33 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:417.33,419.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:449.74,451.30 2 503 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:451.30,453.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:459.2,459.45 1 503 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:459.45,461.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:465.2,466.27 2 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:466.27,472.3 2 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:472.8,472.38 1 500 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:472.38,476.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:480.2,481.24 2 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:481.24,490.17 2 500 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:490.17,492.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:495.2,505.15 3 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:511.52,513.2 1 49500 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:517.45,519.2 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:524.76,528.19 2 49503 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:528.19,530.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:534.2,539.19 3 49502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:539.19,541.17 2 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:541.17,543.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:545.3,545.35 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:548.2,548.27 1 49502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:555.53,557.9 1 1003 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:560.28,561.37 1 500 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:565.30,566.42 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:569.2,569.9 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:570.29,573.4 1 400 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:574.38,577.4 1 100 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:578.35,579.64 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:582.2,591.16 3 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:591.16,593.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:595.2,600.24 4 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:606.67,610.17 2 497 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:610.17,612.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:619.2,624.17 3 496 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:624.17,626.10 2 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:627.30,633.5 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:634.39,640.5 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:641.36,647.5 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:650.3,656.61 2 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:656.61,658.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:660.3,660.24 1 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:663.2,663.25 1 496 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/context.go:667.49,669.2 1 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:41.43,47.2 3 16 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:50.38,52.2 1 5 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:55.33,57.2 1 8 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:62.59,64.27 2 7 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:64.27,66.3 1 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:68.2,69.15 2 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:76.68,77.10 1 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:77.10,79.3 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:83.2,85.27 3 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:85.27,87.3 1 150613 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:89.2,90.13 2 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:95.48,97.2 1 154731 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:104.38,109.74 2 151638 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:109.74,111.3 1 1561 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:116.2,124.12 6 150077 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:129.69,130.10 1 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:130.10,132.3 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:136.2,136.24 1 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:136.24,137.43 1 3097 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:137.43,139.4 1 1546 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:145.2,145.11 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:189.48,190.31 1 1531 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:190.31,192.3 1 1531 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:197.47,198.31 1 1537 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:198.31,201.3 2 1537 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:206.57,207.31 1 16 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:207.31,209.3 1 16 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:220.58,221.31 1 301 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:221.31,232.3 4 301 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:239.39,240.31 1 1204 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:240.31,248.3 3 1204 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:253.43,255.2 1 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:261.44,266.2 4 1522 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:275.79,281.30 2 1539 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:281.30,283.3 1 616 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:283.8,285.3 1 923 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:289.2,291.20 3 1539 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:291.20,293.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:300.2,312.27 5 1538 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:312.27,314.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:318.2,321.39 3 1537 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:344.62,348.33 2 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:348.33,350.3 1 4589 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:354.2,354.10 1 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:354.10,356.3 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:360.2,360.25 1 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:360.25,362.3 1 17 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:366.2,366.32 1 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:366.32,369.3 2 11 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:375.2,376.27 2 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:376.27,393.3 6 150613 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:398.2,403.23 3 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:403.23,415.23 3 1505 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:415.23,417.4 1 301 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:423.3,427.39 2 1505 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:430.2,440.41 3 1548 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:440.41,445.17 2 1539 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:445.17,447.4 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/keys.go:450.2,456.31 3 1546 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:63.73,90.2 14 1020 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:134.63,136.2 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:139.42,143.2 1 506 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:148.49,149.31 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:149.31,151.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:156.60,157.31 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:157.31,159.3 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:164.69,165.31 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:165.31,167.3 1 502 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:173.75,174.31 1 500 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:174.31,176.3 1 500 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:181.55,182.31 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:182.31,184.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:189.51,190.31 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:190.31,192.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:199.64,200.31 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:200.31,207.3 6 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:218.47,220.2 1 2024 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:224.48,226.2 1 1012 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:230.48,232.2 1 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:237.76,240.40 1 3042 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:240.40,242.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:244.2,244.38 1 3042 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:244.38,246.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:248.2,248.12 1 3042 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:261.47,266.41 2 1012 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:266.41,268.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:271.2,272.16 2 1012 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:272.16,274.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:277.2,278.16 2 1012 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:278.16,280.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:282.2,282.9 1 1012 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:285.23,286.50 1 1006 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:286.50,288.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:293.26,294.14 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:295.10,296.50 1 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:296.50,298.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:300.3,301.17 2 6 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:301.17,303.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:307.2,308.16 2 1012 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:308.16,310.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:315.2,315.62 1 1012 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:315.62,317.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:321.2,321.58 1 1012 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:326.60,328.30 2 506 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:328.30,330.3 1 1508 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:333.2,333.56 1 506 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:333.56,335.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:339.2,340.62 2 506 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:340.62,342.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:346.2,346.31 1 506 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:346.31,349.43 2 505 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:349.43,351.4 1 16160 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:356.2,357.16 2 506 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:357.16,359.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:360.2,361.16 2 506 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:361.16,363.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:365.2,381.21 9 506 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:386.82,392.73 2 524 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:392.73,396.43 2 1046 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:396.43,402.18 3 100111 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:402.18,404.5 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:406.4,406.27 1 100107 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:411.3,412.40 2 1042 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:412.40,416.4 1 100106 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:418.3,419.29 2 1042 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:425.2,426.73 2 524 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:426.73,428.3 1 50058 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:429.2,429.16 1 524 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:429.16,431.3 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:433.2,433.73 1 522 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:433.73,435.3 1 50053 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:436.2,436.16 1 522 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:436.16,438.3 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/nonces.go:440.2,446.24 3 520 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:66.39,72.2 1 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:76.54,80.46 3 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:80.46,82.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:84.2,84.12 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:89.54,93.53 3 11 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:93.53,95.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:97.2,98.20 2 11 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:98.20,100.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:102.2,102.12 1 10 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:140.40,142.2 1 1030 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:147.32,148.30 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:148.30,150.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:155.34,156.30 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:156.30,158.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:163.52,164.30 1 5 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:164.30,166.3 1 10 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:178.57,179.30 1 100 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:179.30,181.3 1 200 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:192.38,193.30 1 400 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:193.30,195.3 1 800 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:202.50,223.16 8 519 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:223.16,225.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:226.2,229.16 2 518 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:229.16,231.3 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:236.2,242.28 4 516 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:242.28,245.3 2 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:247.2,247.35 1 516 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:256.67,260.34 2 516 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:260.34,262.3 1 505 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:265.2,266.43 1 516 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:266.43,269.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:272.2,273.29 2 516 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:273.29,274.35 1 50044 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:274.35,276.4 1 515 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:279.2,279.22 1 516 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:279.22,281.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:285.2,291.9 4 515 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:292.23,295.4 1 400 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:296.32,299.4 1 100 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:300.29,301.65 1 5 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:306.2,309.16 2 515 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:309.16,311.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:316.2,319.16 2 515 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:319.16,321.3 1 3 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:325.2,329.32 4 512 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:329.32,331.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:333.2,339.21 3 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:339.21,342.3 2 205 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:344.2,345.28 2 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:345.28,347.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:349.2,350.35 2 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:350.35,353.3 2 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:357.2,358.23 2 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:358.23,360.3 1 206 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:365.2,393.20 13 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:393.20,399.16 3 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:399.16,401.4 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:404.2,404.18 1 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:412.74,419.2 2 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:426.61,429.34 2 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:429.34,431.3 1 505 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:435.2,448.9 5 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:449.23,452.4 1 400 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:453.32,456.4 1 100 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:457.29,458.65 1 5 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:463.2,466.16 2 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:466.16,468.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:473.2,486.16 8 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:486.16,488.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:489.2,492.16 2 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:492.16,494.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:499.2,508.16 5 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:508.16,510.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:511.2,514.16 2 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:514.16,516.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:519.2,519.28 1 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:519.28,521.3 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:521.8,523.3 1 513 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:527.2,536.21 5 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:536.21,539.3 2 208 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:544.2,557.16 9 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:557.16,559.3 1 0 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:563.2,569.59 4 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:569.59,571.3 1 206 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:576.2,590.14 10 514 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:590.14,592.3 1 3 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:594.2,594.12 1 511 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:612.46,614.2 1 10 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:622.50,624.33 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:624.33,632.3 4 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:643.46,645.33 1 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:645.33,653.3 4 1 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:665.27,667.33 1 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:667.33,675.3 4 4 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:682.51,686.37 2 10 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:686.37,688.3 1 7 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:692.2,693.53 2 10 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:693.53,698.60 3 7 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:698.60,700.4 1 2 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:705.3,716.52 9 7 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:720.2,721.41 2 10 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:721.41,723.3 1 510 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:728.2,728.25 1 10 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:728.25,730.3 1 7 +github.com/btcsuite/btcd/btcec/v2/schnorr/musig2/sign.go:733.2,737.54 4 10 diff --git a/btcjson/cmdinfo_test.go b/btcjson/cmdinfo_test.go index 61a693e404c..e41c0a06f03 100644 --- a/btcjson/cmdinfo_test.go +++ b/btcjson/cmdinfo_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcd/btcjson" + "github.com/peercoin/ppcd/btcjson" ) // TestCmdMethod tests the CmdMethod function to ensure it retunrs the expected diff --git a/btcjson/cmdparse_test.go b/btcjson/cmdparse_test.go index f2585edf5cd..b4f7d736262 100644 --- a/btcjson/cmdparse_test.go +++ b/btcjson/cmdparse_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcd/btcjson" + "github.com/peercoin/ppcd/btcjson" ) // TestAssignField tests the assignField function handles supported combinations diff --git a/btcjson/error_test.go b/btcjson/error_test.go index 8eb93c7590c..256bbd3d872 100644 --- a/btcjson/error_test.go +++ b/btcjson/error_test.go @@ -7,7 +7,7 @@ package btcjson_test import ( "testing" - "github.com/btcsuite/btcd/btcjson" + "github.com/peercoin/ppcd/btcjson" ) // TestErrorCodeStringer tests the stringized output for the ErrorCode type. diff --git a/btcjson/help_test.go b/btcjson/help_test.go index 918aa14479b..8afb386a13f 100644 --- a/btcjson/help_test.go +++ b/btcjson/help_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcd/btcjson" + "github.com/peercoin/ppcd/btcjson" ) // TestHelpReflectInternals ensures the various help functions which deal with diff --git a/btcjson/register_test.go b/btcjson/register_test.go index 2d3ab10f3e0..2bf39089243 100644 --- a/btcjson/register_test.go +++ b/btcjson/register_test.go @@ -9,7 +9,7 @@ import ( "sort" "testing" - "github.com/btcsuite/btcd/btcjson" + "github.com/peercoin/ppcd/btcjson" ) // TestUsageFlagStringer tests the stringized output for the UsageFlag type. diff --git a/btcutil/go.mod b/btcutil/go.mod index b03318a461e..bf45fe42a1f 100644 --- a/btcutil/go.mod +++ b/btcutil/go.mod @@ -1,16 +1,16 @@ module github.com/btcsuite/btcd/btcutil -go 1.16 +go 1.21.4 require ( github.com/aead/siphash v1.0.1 - github.com/btcsuite/btcd v0.23.0 + github.com/btcsuite/btcd v0.23.4 github.com/btcsuite/btcd/btcec/v2 v2.1.3 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 github.com/davecgh/go-spew v1.1.1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + golang.org/x/crypto v0.14.0 ) replace github.com/btcsuite/btcd => ../ diff --git a/btcutil/go.sum b/btcutil/go.sum index 5bd6215f1f1..e920241df2f 100644 --- a/btcutil/go.sum +++ b/btcutil/go.sum @@ -57,6 +57,7 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= diff --git a/btcutil/psbt/go.mod b/btcutil/psbt/go.mod index 80f57fc1b33..aeeed157848 100644 --- a/btcutil/psbt/go.mod +++ b/btcutil/psbt/go.mod @@ -1,14 +1,12 @@ module github.com/btcsuite/btcd/btcutil/psbt -go 1.17 +go 1.21.4 require ( - github.com/btcsuite/btcd v0.23.0 + github.com/btcsuite/btcd v0.23.4 github.com/btcsuite/btcd/btcec/v2 v2.1.3 github.com/btcsuite/btcd/btcutil v1.1.0 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 - github.com/davecgh/go-spew v1.1.1 - github.com/stretchr/testify v1.7.0 ) require ( @@ -16,8 +14,8 @@ require ( github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/sys v0.13.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/btcutil/psbt/go.sum b/btcutil/psbt/go.sum index 4a874c628e1..ac3b74a7534 100644 --- a/btcutil/psbt/go.sum +++ b/btcutil/psbt/go.sum @@ -50,6 +50,7 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -65,6 +66,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/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= diff --git a/database/error_test.go b/database/error_test.go index 759d26e1648..89708dfebc9 100644 --- a/database/error_test.go +++ b/database/error_test.go @@ -8,7 +8,7 @@ import ( "errors" "testing" - "github.com/btcsuite/btcd/database" + "github.com/peercoin/ppcd/database" ) // TestErrorCodeStringer tests the stringized output for the ErrorCode type. diff --git a/database/ffldb/db.go b/database/ffldb/db.go index 1751c936a9b..a7714c99bf5 100644 --- a/database/ffldb/db.go +++ b/database/ffldb/db.go @@ -17,7 +17,7 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/database" - "github.com/btcsuite/btcd/database/internal/treap" + "github.com/btcsuite/btcd/database/treap" "github.com/btcsuite/btcd/wire" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/comparer" diff --git a/database/ffldb/dbcache.go b/database/ffldb/dbcache.go index ec42ee969eb..7a0523a1679 100644 --- a/database/ffldb/dbcache.go +++ b/database/ffldb/dbcache.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "github.com/btcsuite/btcd/database/internal/treap" + "github.com/btcsuite/btcd/database/treap" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/util" diff --git a/database/ffldb/driver_test.go b/database/ffldb/driver_test.go index 794e8e19124..f5fabc2c585 100644 --- a/database/ffldb/driver_test.go +++ b/database/ffldb/driver_test.go @@ -16,7 +16,7 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/database" - "github.com/btcsuite/btcd/database/ffldb" + "github.com/peercoin/ppcd/database/ffldb" ) // dbType is the database type name for this driver. diff --git a/database/ffldb/ldbtreapiter.go b/database/ffldb/ldbtreapiter.go index 10ce207c7f0..2b5ddd7b246 100644 --- a/database/ffldb/ldbtreapiter.go +++ b/database/ffldb/ldbtreapiter.go @@ -5,7 +5,7 @@ package ffldb import ( - "github.com/btcsuite/btcd/database/internal/treap" + "github.com/btcsuite/btcd/database/treap" "github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/util" ) diff --git a/database/treap/README.md b/database/treap/README.md new file mode 100644 index 00000000000..14c3159a503 --- /dev/null +++ b/database/treap/README.md @@ -0,0 +1,39 @@ +treap +===== + +[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions) +[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) +[![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/database/internal/treap?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/database/internal/treap) + +Package treap implements a treap data structure that is used to hold ordered +key/value pairs using a combination of binary search tree and heap semantics. +It is a self-organizing and randomized data structure that doesn't require +complex operations to maintain balance. Search, insert, and delete +operations are all O(log n). Both mutable and immutable variants are provided. + +The mutable variant is typically faster since it is able to simply update the +treap when modifications are made. However, a mutable treap is not safe for +concurrent access without careful use of locking by the caller and care must be +taken when iterating since it can change out from under the iterator. + +The immutable variant works by creating a new version of the treap for all +mutations by replacing modified nodes with new nodes that have updated values +while sharing all unmodified nodes with the previous version. This is extremely +useful in concurrent applications since the caller only has to atomically +replace the treap pointer with the newly returned version after performing any +mutations. All readers can simply use their existing pointer as a snapshot +since the treap it points to is immutable. This effectively provides O(1) +snapshot capability with efficient memory usage characteristics since the old +nodes only remain allocated until there are no longer any references to them. + +Package treap is licensed under the copyfree ISC license. + +## Usage + +This package is only used internally in the database code and as such is not +available for use outside of it. + +## License + +Package treap is licensed under the [copyfree](http://copyfree.org) ISC +License. diff --git a/database/treap/common.go b/database/treap/common.go new file mode 100644 index 00000000000..090a7bd5ab0 --- /dev/null +++ b/database/treap/common.go @@ -0,0 +1,136 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package treap + +import ( + "math/rand" + "time" +) + +const ( + // staticDepth is the size of the static array to use for keeping track + // of the parent stack during treap iteration. Since a treap has a very + // high probability that the tree height is logarithmic, it is + // exceedingly unlikely that the parent stack will ever exceed this size + // even for extremely large numbers of items. + staticDepth = 128 + + // nodeFieldsSize is the size the fields of each node takes excluding + // the contents of the key and value. It assumes 64-bit pointers so + // technically it is smaller on 32-bit platforms, but overestimating the + // size in that case is acceptable since it avoids the need to import + // unsafe. It consists of 24-bytes for each key and value + 8 bytes for + // each of the priority, left, and right fields (24*2 + 8*3). + nodeFieldsSize = 72 +) + +var ( + // emptySlice is used for keys that have no value associated with them + // so callers can distinguish between a key that does not exist and one + // that has no value associated with it. + emptySlice = make([]byte, 0) +) + +// treapNode represents a node in the treap. +type treapNode struct { + key []byte + value []byte + priority int + left *treapNode + right *treapNode +} + +// nodeSize returns the number of bytes the specified node occupies including +// the struct fields and the contents of the key and value. +func nodeSize(node *treapNode) uint64 { + return nodeFieldsSize + uint64(len(node.key)+len(node.value)) +} + +// newTreapNode returns a new node from the given key, value, and priority. The +// node is not initially linked to any others. +func newTreapNode(key, value []byte, priority int) *treapNode { + return &treapNode{key: key, value: value, priority: priority} +} + +// parentStack represents a stack of parent treap nodes that are used during +// iteration. It consists of a static array for holding the parents and a +// dynamic overflow slice. It is extremely unlikely the overflow will ever be +// hit during normal operation, however, since a treap's height is +// probabilistic, the overflow case needs to be handled properly. This approach +// is used because it is much more efficient for the majority case than +// dynamically allocating heap space every time the treap is iterated. +type parentStack struct { + index int + items [staticDepth]*treapNode + overflow []*treapNode +} + +// Len returns the current number of items in the stack. +func (s *parentStack) Len() int { + return s.index +} + +// At returns the item n number of items from the top of the stack, where 0 is +// the topmost item, without removing it. It returns nil if n exceeds the +// number of items on the stack. +func (s *parentStack) At(n int) *treapNode { + index := s.index - n - 1 + if index < 0 { + return nil + } + + if index < staticDepth { + return s.items[index] + } + + return s.overflow[index-staticDepth] +} + +// Pop removes the top item from the stack. It returns nil if the stack is +// empty. +func (s *parentStack) Pop() *treapNode { + if s.index == 0 { + return nil + } + + s.index-- + if s.index < staticDepth { + node := s.items[s.index] + s.items[s.index] = nil + return node + } + + node := s.overflow[s.index-staticDepth] + s.overflow[s.index-staticDepth] = nil + return node +} + +// Push pushes the passed item onto the top of the stack. +func (s *parentStack) Push(node *treapNode) { + if s.index < staticDepth { + s.items[s.index] = node + s.index++ + return + } + + // This approach is used over append because reslicing the slice to pop + // the item causes the compiler to make unneeded allocations. Also, + // since the max number of items is related to the tree depth which + // requires expontentially more items to increase, only increase the cap + // one item at a time. This is more intelligent than the generic append + // expansion algorithm which often doubles the cap. + index := s.index - staticDepth + if index+1 > cap(s.overflow) { + overflow := make([]*treapNode, index+1) + copy(overflow, s.overflow) + s.overflow = overflow + } + s.overflow[index] = node + s.index++ +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} diff --git a/database/treap/common_test.go b/database/treap/common_test.go new file mode 100644 index 00000000000..c43e678de7a --- /dev/null +++ b/database/treap/common_test.go @@ -0,0 +1,121 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package treap + +import ( + "encoding/binary" + "encoding/hex" + "math/rand" + "reflect" + "testing" +) + +// fromHex converts the passed hex string into a byte slice and will panic if +// there is an error. This is only provided for the hard-coded constants so +// errors in the source code can be detected. It will only (and must only) be +// called for initialization purposes. +func fromHex(s string) []byte { + r, err := hex.DecodeString(s) + if err != nil { + panic("invalid hex in source file: " + s) + } + return r +} + +// serializeUint32 returns the big-endian encoding of the passed uint32. +func serializeUint32(ui uint32) []byte { + var ret [4]byte + binary.BigEndian.PutUint32(ret[:], ui) + return ret[:] +} + +// TestParentStack ensures the treapParentStack functionality works as intended. +func TestParentStack(t *testing.T) { + t.Parallel() + + tests := []struct { + numNodes int + }{ + {numNodes: 1}, + {numNodes: staticDepth}, + {numNodes: staticDepth + 1}, // Test dynamic code paths + } + +testLoop: + for i, test := range tests { + nodes := make([]*treapNode, 0, test.numNodes) + for j := 0; j < test.numNodes; j++ { + var key [4]byte + binary.BigEndian.PutUint32(key[:], uint32(j)) + node := newTreapNode(key[:], key[:], 0) + nodes = append(nodes, node) + } + + // Push all of the nodes onto the parent stack while testing + // various stack properties. + stack := &parentStack{} + for j, node := range nodes { + stack.Push(node) + + // Ensure the stack length is the expected value. + if stack.Len() != j+1 { + t.Errorf("Len #%d (%d): unexpected stack "+ + "length - got %d, want %d", i, j, + stack.Len(), j+1) + continue testLoop + } + + // Ensure the node at each index is the expected one. + for k := 0; k <= j; k++ { + atNode := stack.At(j - k) + if !reflect.DeepEqual(atNode, nodes[k]) { + t.Errorf("At #%d (%d): mismatched node "+ + "- got %v, want %v", i, j-k, + atNode, nodes[k]) + continue testLoop + } + } + } + + // Ensure each popped node is the expected one. + for j := 0; j < len(nodes); j++ { + node := stack.Pop() + expected := nodes[len(nodes)-j-1] + if !reflect.DeepEqual(node, expected) { + t.Errorf("At #%d (%d): mismatched node - "+ + "got %v, want %v", i, j, node, expected) + continue testLoop + } + } + + // Ensure the stack is now empty. + if stack.Len() != 0 { + t.Errorf("Len #%d: stack is not empty - got %d", i, + stack.Len()) + continue testLoop + } + + // Ensure attempting to retrieve a node at an index beyond the + // stack's length returns nil. + if node := stack.At(2); node != nil { + t.Errorf("At #%d: did not give back nil - got %v", i, + node) + continue testLoop + } + + // Ensure attempting to pop a node from an empty stack returns + // nil. + if node := stack.Pop(); node != nil { + t.Errorf("Pop #%d: did not give back nil - got %v", i, + node) + continue testLoop + } + } +} + +func init() { + // Force the same pseudo random numbers for each test run. + rand.Seed(0) +} diff --git a/database/treap/doc.go b/database/treap/doc.go new file mode 100644 index 00000000000..4f46e057c12 --- /dev/null +++ b/database/treap/doc.go @@ -0,0 +1,27 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +/* +Package treap implements a treap data structure that is used to hold ordered +key/value pairs using a combination of binary search tree and heap semantics. +It is a self-organizing and randomized data structure that doesn't require +complex operations to to maintain balance. Search, insert, and delete +operations are all O(log n). Both mutable and immutable variants are provided. + +The mutable variant is typically faster since it is able to simply update the +treap when modifications are made. However, a mutable treap is not safe for +concurrent access without careful use of locking by the caller and care must be +taken when iterating since it can change out from under the iterator. + +The immutable variant works by creating a new version of the treap for all +mutations by replacing modified nodes with new nodes that have updated values +while sharing all unmodified nodes with the previous version. This is extremely +useful in concurrent applications since the caller only has to atomically +replace the treap pointer with the newly returned version after performing any +mutations. All readers can simply use their existing pointer as a snapshot +since the treap it points to is immutable. This effectively provides O(1) +snapshot capability with efficient memory usage characteristics since the old +nodes only remain allocated until there are no longer any references to them. +*/ +package treap diff --git a/database/treap/immutable.go b/database/treap/immutable.go new file mode 100644 index 00000000000..a6e13ff4a50 --- /dev/null +++ b/database/treap/immutable.go @@ -0,0 +1,360 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package treap + +import ( + "bytes" + "math/rand" +) + +// cloneTreapNode returns a shallow copy of the passed node. +func cloneTreapNode(node *treapNode) *treapNode { + return &treapNode{ + key: node.key, + value: node.value, + priority: node.priority, + left: node.left, + right: node.right, + } +} + +// Immutable represents a treap data structure which is used to hold ordered +// key/value pairs using a combination of binary search tree and heap semantics. +// It is a self-organizing and randomized data structure that doesn't require +// complex operations to maintain balance. Search, insert, and delete +// operations are all O(log n). In addition, it provides O(1) snapshots for +// multi-version concurrency control (MVCC). +// +// All operations which result in modifying the treap return a new version of +// the treap with only the modified nodes updated. All unmodified nodes are +// shared with the previous version. This is extremely useful in concurrent +// applications since the caller only has to atomically replace the treap +// pointer with the newly returned version after performing any mutations. All +// readers can simply use their existing pointer as a snapshot since the treap +// it points to is immutable. This effectively provides O(1) snapshot +// capability with efficient memory usage characteristics since the old nodes +// only remain allocated until there are no longer any references to them. +type Immutable struct { + root *treapNode + count int + + // totalSize is the best estimate of the total size of of all data in + // the treap including the keys, values, and node sizes. + totalSize uint64 +} + +// newImmutable returns a new immutable treap given the passed parameters. +func newImmutable(root *treapNode, count int, totalSize uint64) *Immutable { + return &Immutable{root: root, count: count, totalSize: totalSize} +} + +// Len returns the number of items stored in the treap. +func (t *Immutable) Len() int { + return t.count +} + +// Size returns a best estimate of the total number of bytes the treap is +// consuming including all of the fields used to represent the nodes as well as +// the size of the keys and values. Shared values are not detected, so the +// returned size assumes each value is pointing to different memory. +func (t *Immutable) Size() uint64 { + return t.totalSize +} + +// get returns the treap node that contains the passed key. It will return nil +// when the key does not exist. +func (t *Immutable) get(key []byte) *treapNode { + for node := t.root; node != nil; { + // Traverse left or right depending on the result of the + // comparison. + compareResult := bytes.Compare(key, node.key) + if compareResult < 0 { + node = node.left + continue + } + if compareResult > 0 { + node = node.right + continue + } + + // The key exists. + return node + } + + // A nil node was reached which means the key does not exist. + return nil +} + +// Has returns whether or not the passed key exists. +func (t *Immutable) Has(key []byte) bool { + if node := t.get(key); node != nil { + return true + } + return false +} + +// Get returns the value for the passed key. The function will return nil when +// the key does not exist. +func (t *Immutable) Get(key []byte) []byte { + if node := t.get(key); node != nil { + return node.value + } + return nil +} + +// Put inserts the passed key/value pair. +func (t *Immutable) Put(key, value []byte) *Immutable { + // Use an empty byte slice for the value when none was provided. This + // ultimately allows key existence to be determined from the value since + // an empty byte slice is distinguishable from nil. + if value == nil { + value = emptySlice + } + + // The node is the root of the tree if there isn't already one. + if t.root == nil { + root := newTreapNode(key, value, rand.Int()) + return newImmutable(root, 1, nodeSize(root)) + } + + // Find the binary tree insertion point and construct a replaced list of + // parents while doing so. This is done because this is an immutable + // data structure so regardless of where in the treap the new key/value + // pair ends up, all ancestors up to and including the root need to be + // replaced. + // + // When the key matches an entry already in the treap, replace the node + // with a new one that has the new value set and return. + var parents parentStack + var compareResult int + for node := t.root; node != nil; { + // Clone the node and link its parent to it if needed. + nodeCopy := cloneTreapNode(node) + if oldParent := parents.At(0); oldParent != nil { + if oldParent.left == node { + oldParent.left = nodeCopy + } else { + oldParent.right = nodeCopy + } + } + parents.Push(nodeCopy) + + // Traverse left or right depending on the result of comparing + // the keys. + compareResult = bytes.Compare(key, node.key) + if compareResult < 0 { + node = node.left + continue + } + if compareResult > 0 { + node = node.right + continue + } + + // The key already exists, so update its value. + nodeCopy.value = value + + // Return new immutable treap with the replaced node and + // ancestors up to and including the root of the tree. + newRoot := parents.At(parents.Len() - 1) + newTotalSize := t.totalSize - uint64(len(node.value)) + + uint64(len(value)) + return newImmutable(newRoot, t.count, newTotalSize) + } + + // Link the new node into the binary tree in the correct position. + node := newTreapNode(key, value, rand.Int()) + parent := parents.At(0) + if compareResult < 0 { + parent.left = node + } else { + parent.right = node + } + + // Perform any rotations needed to maintain the min-heap and replace + // the ancestors up to and including the tree root. + newRoot := parents.At(parents.Len() - 1) + for parents.Len() > 0 { + // There is nothing left to do when the node's priority is + // greater than or equal to its parent's priority. + parent = parents.Pop() + if node.priority >= parent.priority { + break + } + + // Perform a right rotation if the node is on the left side or + // a left rotation if the node is on the right side. + if parent.left == node { + node.right, parent.left = parent, node.right + } else { + node.left, parent.right = parent, node.left + } + + // Either set the new root of the tree when there is no + // grandparent or relink the grandparent to the node based on + // which side the old parent the node is replacing was on. + grandparent := parents.At(0) + if grandparent == nil { + newRoot = node + } else if grandparent.left == parent { + grandparent.left = node + } else { + grandparent.right = node + } + } + + return newImmutable(newRoot, t.count+1, t.totalSize+nodeSize(node)) +} + +// Delete removes the passed key from the treap and returns the resulting treap +// if it exists. The original immutable treap is returned if the key does not +// exist. +func (t *Immutable) Delete(key []byte) *Immutable { + // Find the node for the key while constructing a list of parents while + // doing so. + var parents parentStack + var delNode *treapNode + for node := t.root; node != nil; { + parents.Push(node) + + // Traverse left or right depending on the result of the + // comparison. + compareResult := bytes.Compare(key, node.key) + if compareResult < 0 { + node = node.left + continue + } + if compareResult > 0 { + node = node.right + continue + } + + // The key exists. + delNode = node + break + } + + // There is nothing to do if the key does not exist. + if delNode == nil { + return t + } + + // When the only node in the tree is the root node and it is the one + // being deleted, there is nothing else to do besides removing it. + parent := parents.At(1) + if parent == nil && delNode.left == nil && delNode.right == nil { + return newImmutable(nil, 0, 0) + } + + // Construct a replaced list of parents and the node to delete itself. + // This is done because this is an immutable data structure and + // therefore all ancestors of the node that will be deleted, up to and + // including the root, need to be replaced. + var newParents parentStack + for i := parents.Len(); i > 0; i-- { + node := parents.At(i - 1) + nodeCopy := cloneTreapNode(node) + if oldParent := newParents.At(0); oldParent != nil { + if oldParent.left == node { + oldParent.left = nodeCopy + } else { + oldParent.right = nodeCopy + } + } + newParents.Push(nodeCopy) + } + delNode = newParents.Pop() + parent = newParents.At(0) + + // Perform rotations to move the node to delete to a leaf position while + // maintaining the min-heap while replacing the modified children. + var child *treapNode + newRoot := newParents.At(newParents.Len() - 1) + for delNode.left != nil || delNode.right != nil { + // Choose the child with the higher priority. + var isLeft bool + if delNode.left == nil { + child = delNode.right + } else if delNode.right == nil { + child = delNode.left + isLeft = true + } else if delNode.left.priority >= delNode.right.priority { + child = delNode.left + isLeft = true + } else { + child = delNode.right + } + + // Rotate left or right depending on which side the child node + // is on. This has the effect of moving the node to delete + // towards the bottom of the tree while maintaining the + // min-heap. + child = cloneTreapNode(child) + if isLeft { + child.right, delNode.left = delNode, child.right + } else { + child.left, delNode.right = delNode, child.left + } + + // Either set the new root of the tree when there is no + // grandparent or relink the grandparent to the node based on + // which side the old parent the node is replacing was on. + // + // Since the node to be deleted was just moved down a level, the + // new grandparent is now the current parent and the new parent + // is the current child. + if parent == nil { + newRoot = child + } else if parent.left == delNode { + parent.left = child + } else { + parent.right = child + } + + // The parent for the node to delete is now what was previously + // its child. + parent = child + } + + // Delete the node, which is now a leaf node, by disconnecting it from + // its parent. + if parent.right == delNode { + parent.right = nil + } else { + parent.left = nil + } + + return newImmutable(newRoot, t.count-1, t.totalSize-nodeSize(delNode)) +} + +// ForEach invokes the passed function with every key/value pair in the treap +// in ascending order. +func (t *Immutable) ForEach(fn func(k, v []byte) bool) { + // Add the root node and all children to the left of it to the list of + // nodes to traverse and loop until they, and all of their child nodes, + // have been traversed. + var parents parentStack + for node := t.root; node != nil; node = node.left { + parents.Push(node) + } + for parents.Len() > 0 { + node := parents.Pop() + if !fn(node.key, node.value) { + return + } + + // Extend the nodes to traverse by all children to the left of + // the current node's right child. + for node := node.right; node != nil; node = node.left { + parents.Push(node) + } + } +} + +// NewImmutable returns a new empty immutable treap ready for use. See the +// documentation for the Immutable structure for more details. +func NewImmutable() *Immutable { + return &Immutable{} +} diff --git a/database/treap/immutable_test.go b/database/treap/immutable_test.go new file mode 100644 index 00000000000..e0a1cb4af6b --- /dev/null +++ b/database/treap/immutable_test.go @@ -0,0 +1,497 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package treap + +import ( + "bytes" + "crypto/sha256" + "testing" +) + +// TestImmutableEmpty ensures calling functions on an empty immutable treap +// works as expected. +func TestImmutableEmpty(t *testing.T) { + t.Parallel() + + // Ensure the treap length is the expected value. + testTreap := NewImmutable() + if gotLen := testTreap.Len(); gotLen != 0 { + t.Fatalf("Len: unexpected length - got %d, want %d", gotLen, 0) + } + + // Ensure the reported size is 0. + if gotSize := testTreap.Size(); gotSize != 0 { + t.Fatalf("Size: unexpected byte size - got %d, want 0", + gotSize) + } + + // Ensure there are no errors with requesting keys from an empty treap. + key := serializeUint32(0) + if gotVal := testTreap.Has(key); gotVal { + t.Fatalf("Has: unexpected result - got %v, want false", gotVal) + } + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get: unexpected result - got %x, want nil", gotVal) + } + + // Ensure there are no panics when deleting keys from an empty treap. + testTreap.Delete(key) + + // Ensure the number of keys iterated by ForEach on an empty treap is + // zero. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + numIterated++ + return true + }) + if numIterated != 0 { + t.Fatalf("ForEach: unexpected iterate count - got %d, want 0", + numIterated) + } +} + +// TestImmutableSequential ensures that putting keys into an immutable treap in +// sequential order works as expected. +func TestImmutableSequential(t *testing.T) { + t.Parallel() + + // Insert a bunch of sequential keys while checking several of the treap + // functions work as expected. + expectedSize := uint64(0) + numItems := 1000 + testTreap := NewImmutable() + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + testTreap = testTreap.Put(key, key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != i+1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, i+1) + } + + // Ensure the treap has the key. + if !testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is not in treap", i, key) + } + + // Get the key from the treap and ensure it is the expected + // value. + if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) { + t.Fatalf("Get #%d: unexpected value - got %x, want %x", + i, gotVal, key) + } + + // Ensure the expected size is reported. + expectedSize += (nodeFieldsSize + 8) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } + + // Ensure the all keys are iterated by ForEach in order. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + wantKey := serializeUint32(uint32(numIterated)) + + // Ensure the key is as expected. + if !bytes.Equal(k, wantKey) { + t.Fatalf("ForEach #%d: unexpected key - got %x, want %x", + numIterated, k, wantKey) + } + + // Ensure the value is as expected. + if !bytes.Equal(v, wantKey) { + t.Fatalf("ForEach #%d: unexpected value - got %x, want %x", + numIterated, v, wantKey) + } + + numIterated++ + return true + }) + + // Ensure all items were iterated. + if numIterated != numItems { + t.Fatalf("ForEach: unexpected iterate count - got %d, want %d", + numIterated, numItems) + } + + // Delete the keys one-by-one while checking several of the treap + // functions work as expected. + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + testTreap = testTreap.Delete(key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != numItems-i-1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, numItems-i-1) + } + + // Ensure the treap no longer has the key. + if testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is in treap", i, key) + } + + // Get the key that no longer exists from the treap and ensure + // it is nil. + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get #%d: unexpected value - got %x, want nil", + i, gotVal) + } + + // Ensure the expected size is reported. + expectedSize -= (nodeFieldsSize + 8) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } +} + +// TestImmutableReverseSequential ensures that putting keys into an immutable +// treap in reverse sequential order works as expected. +func TestImmutableReverseSequential(t *testing.T) { + t.Parallel() + + // Insert a bunch of sequential keys while checking several of the treap + // functions work as expected. + expectedSize := uint64(0) + numItems := 1000 + testTreap := NewImmutable() + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(numItems - i - 1)) + testTreap = testTreap.Put(key, key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != i+1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, i+1) + } + + // Ensure the treap has the key. + if !testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is not in treap", i, key) + } + + // Get the key from the treap and ensure it is the expected + // value. + if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) { + t.Fatalf("Get #%d: unexpected value - got %x, want %x", + i, gotVal, key) + } + + // Ensure the expected size is reported. + expectedSize += (nodeFieldsSize + 8) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } + + // Ensure the all keys are iterated by ForEach in order. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + wantKey := serializeUint32(uint32(numIterated)) + + // Ensure the key is as expected. + if !bytes.Equal(k, wantKey) { + t.Fatalf("ForEach #%d: unexpected key - got %x, want %x", + numIterated, k, wantKey) + } + + // Ensure the value is as expected. + if !bytes.Equal(v, wantKey) { + t.Fatalf("ForEach #%d: unexpected value - got %x, want %x", + numIterated, v, wantKey) + } + + numIterated++ + return true + }) + + // Ensure all items were iterated. + if numIterated != numItems { + t.Fatalf("ForEach: unexpected iterate count - got %d, want %d", + numIterated, numItems) + } + + // Delete the keys one-by-one while checking several of the treap + // functions work as expected. + for i := 0; i < numItems; i++ { + // Intentionally use the reverse order they were inserted here. + key := serializeUint32(uint32(i)) + testTreap = testTreap.Delete(key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != numItems-i-1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, numItems-i-1) + } + + // Ensure the treap no longer has the key. + if testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is in treap", i, key) + } + + // Get the key that no longer exists from the treap and ensure + // it is nil. + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get #%d: unexpected value - got %x, want nil", + i, gotVal) + } + + // Ensure the expected size is reported. + expectedSize -= (nodeFieldsSize + 8) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } +} + +// TestImmutableUnordered ensures that putting keys into an immutable treap in +// no paritcular order works as expected. +func TestImmutableUnordered(t *testing.T) { + t.Parallel() + + // Insert a bunch of out-of-order keys while checking several of the + // treap functions work as expected. + expectedSize := uint64(0) + numItems := 1000 + testTreap := NewImmutable() + for i := 0; i < numItems; i++ { + // Hash the serialized int to generate out-of-order keys. + hash := sha256.Sum256(serializeUint32(uint32(i))) + key := hash[:] + testTreap = testTreap.Put(key, key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != i+1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, i+1) + } + + // Ensure the treap has the key. + if !testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is not in treap", i, key) + } + + // Get the key from the treap and ensure it is the expected + // value. + if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) { + t.Fatalf("Get #%d: unexpected value - got %x, want %x", + i, gotVal, key) + } + + // Ensure the expected size is reported. + expectedSize += nodeFieldsSize + uint64(len(key)+len(key)) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } + + // Delete the keys one-by-one while checking several of the treap + // functions work as expected. + for i := 0; i < numItems; i++ { + // Hash the serialized int to generate out-of-order keys. + hash := sha256.Sum256(serializeUint32(uint32(i))) + key := hash[:] + testTreap = testTreap.Delete(key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != numItems-i-1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, numItems-i-1) + } + + // Ensure the treap no longer has the key. + if testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is in treap", i, key) + } + + // Get the key that no longer exists from the treap and ensure + // it is nil. + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get #%d: unexpected value - got %x, want nil", + i, gotVal) + } + + // Ensure the expected size is reported. + expectedSize -= (nodeFieldsSize + 64) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } +} + +// TestImmutableDuplicatePut ensures that putting a duplicate key into an +// immutable treap works as expected. +func TestImmutableDuplicatePut(t *testing.T) { + t.Parallel() + + expectedVal := []byte("testval") + expectedSize := uint64(0) + numItems := 1000 + testTreap := NewImmutable() + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + testTreap = testTreap.Put(key, key) + expectedSize += nodeFieldsSize + uint64(len(key)+len(key)) + + // Put a duplicate key with the expected final value. + testTreap = testTreap.Put(key, expectedVal) + + // Ensure the key still exists and is the new value. + if gotVal := testTreap.Has(key); !gotVal { + t.Fatalf("Has: unexpected result - got %v, want true", + gotVal) + } + if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, expectedVal) { + t.Fatalf("Get: unexpected result - got %x, want %x", + gotVal, expectedVal) + } + + // Ensure the expected size is reported. + expectedSize -= uint64(len(key)) + expectedSize += uint64(len(expectedVal)) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size: unexpected byte size - got %d, want %d", + gotSize, expectedSize) + } + } +} + +// TestImmutableNilValue ensures that putting a nil value into an immutable +// treap results in a key being added with an empty byte slice. +func TestImmutableNilValue(t *testing.T) { + t.Parallel() + + key := serializeUint32(0) + + // Put the key with a nil value. + testTreap := NewImmutable() + testTreap = testTreap.Put(key, nil) + + // Ensure the key exists and is an empty byte slice. + if gotVal := testTreap.Has(key); !gotVal { + t.Fatalf("Has: unexpected result - got %v, want true", gotVal) + } + if gotVal := testTreap.Get(key); gotVal == nil { + t.Fatalf("Get: unexpected result - got nil, want empty slice") + } + if gotVal := testTreap.Get(key); len(gotVal) != 0 { + t.Fatalf("Get: unexpected result - got %x, want empty slice", + gotVal) + } +} + +// TestImmutableForEachStopIterator ensures that returning false from the ForEach +// callback on an immutable treap stops iteration early. +func TestImmutableForEachStopIterator(t *testing.T) { + t.Parallel() + + // Insert a few keys. + numItems := 10 + testTreap := NewImmutable() + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + testTreap = testTreap.Put(key, key) + } + + // Ensure ForEach exits early on false return by caller. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + numIterated++ + return numIterated != numItems/2 + }) + if numIterated != numItems/2 { + t.Fatalf("ForEach: unexpected iterate count - got %d, want %d", + numIterated, numItems/2) + } +} + +// TestImmutableSnapshot ensures that immutable treaps are actually immutable by +// keeping a reference to the previous treap, performing a mutation, and then +// ensuring the referenced treap does not have the mutation applied. +func TestImmutableSnapshot(t *testing.T) { + t.Parallel() + + // Insert a bunch of sequential keys while checking several of the treap + // functions work as expected. + expectedSize := uint64(0) + numItems := 1000 + testTreap := NewImmutable() + for i := 0; i < numItems; i++ { + treapSnap := testTreap + + key := serializeUint32(uint32(i)) + testTreap = testTreap.Put(key, key) + + // Ensure the length of the treap snapshot is the expected + // value. + if gotLen := treapSnap.Len(); gotLen != i { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, i) + } + + // Ensure the treap snapshot does not have the key. + if treapSnap.Has(key) { + t.Fatalf("Has #%d: key %q is in treap", i, key) + } + + // Get the key that doesn't exist in the treap snapshot and + // ensure it is nil. + if gotVal := treapSnap.Get(key); gotVal != nil { + t.Fatalf("Get #%d: unexpected value - got %x, want nil", + i, gotVal) + } + + // Ensure the expected size is reported. + if gotSize := treapSnap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + expectedSize += (nodeFieldsSize + 8) + } + + // Delete the keys one-by-one while checking several of the treap + // functions work as expected. + for i := 0; i < numItems; i++ { + treapSnap := testTreap + + key := serializeUint32(uint32(i)) + testTreap = testTreap.Delete(key) + + // Ensure the length of the treap snapshot is the expected + // value. + if gotLen := treapSnap.Len(); gotLen != numItems-i { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, numItems-i) + } + + // Ensure the treap snapshot still has the key. + if !treapSnap.Has(key) { + t.Fatalf("Has #%d: key %q is not in treap", i, key) + } + + // Get the key from the treap snapshot and ensure it is still + // the expected value. + if gotVal := treapSnap.Get(key); !bytes.Equal(gotVal, key) { + t.Fatalf("Get #%d: unexpected value - got %x, want %x", + i, gotVal, key) + } + + // Ensure the expected size is reported. + if gotSize := treapSnap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + expectedSize -= (nodeFieldsSize + 8) + } +} diff --git a/database/treap/mutable.go b/database/treap/mutable.go new file mode 100644 index 00000000000..84ebe6715f3 --- /dev/null +++ b/database/treap/mutable.go @@ -0,0 +1,278 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package treap + +import ( + "bytes" + "math/rand" +) + +// Mutable represents a treap data structure which is used to hold ordered +// key/value pairs using a combination of binary search tree and heap semantics. +// It is a self-organizing and randomized data structure that doesn't require +// complex operations to maintain balance. Search, insert, and delete +// operations are all O(log n). +type Mutable struct { + root *treapNode + count int + + // totalSize is the best estimate of the total size of of all data in + // the treap including the keys, values, and node sizes. + totalSize uint64 +} + +// Len returns the number of items stored in the treap. +func (t *Mutable) Len() int { + return t.count +} + +// Size returns a best estimate of the total number of bytes the treap is +// consuming including all of the fields used to represent the nodes as well as +// the size of the keys and values. Shared values are not detected, so the +// returned size assumes each value is pointing to different memory. +func (t *Mutable) Size() uint64 { + return t.totalSize +} + +// get returns the treap node that contains the passed key and its parent. When +// the found node is the root of the tree, the parent will be nil. When the key +// does not exist, both the node and the parent will be nil. +func (t *Mutable) get(key []byte) (*treapNode, *treapNode) { + var parent *treapNode + for node := t.root; node != nil; { + // Traverse left or right depending on the result of the + // comparison. + compareResult := bytes.Compare(key, node.key) + if compareResult < 0 { + parent = node + node = node.left + continue + } + if compareResult > 0 { + parent = node + node = node.right + continue + } + + // The key exists. + return node, parent + } + + // A nil node was reached which means the key does not exist. + return nil, nil +} + +// Has returns whether or not the passed key exists. +func (t *Mutable) Has(key []byte) bool { + if node, _ := t.get(key); node != nil { + return true + } + return false +} + +// Get returns the value for the passed key. The function will return nil when +// the key does not exist. +func (t *Mutable) Get(key []byte) []byte { + if node, _ := t.get(key); node != nil { + return node.value + } + return nil +} + +// relinkGrandparent relinks the node into the treap after it has been rotated +// by changing the passed grandparent's left or right pointer, depending on +// where the old parent was, to point at the passed node. Otherwise, when there +// is no grandparent, it means the node is now the root of the tree, so update +// it accordingly. +func (t *Mutable) relinkGrandparent(node, parent, grandparent *treapNode) { + // The node is now the root of the tree when there is no grandparent. + if grandparent == nil { + t.root = node + return + } + + // Relink the grandparent's left or right pointer based on which side + // the old parent was. + if grandparent.left == parent { + grandparent.left = node + } else { + grandparent.right = node + } +} + +// Put inserts the passed key/value pair. +func (t *Mutable) Put(key, value []byte) { + // Use an empty byte slice for the value when none was provided. This + // ultimately allows key existence to be determined from the value since + // an empty byte slice is distinguishable from nil. + if value == nil { + value = emptySlice + } + + // The node is the root of the tree if there isn't already one. + if t.root == nil { + node := newTreapNode(key, value, rand.Int()) + t.count = 1 + t.totalSize = nodeSize(node) + t.root = node + return + } + + // Find the binary tree insertion point and construct a list of parents + // while doing so. When the key matches an entry already in the treap, + // just update its value and return. + var parents parentStack + var compareResult int + for node := t.root; node != nil; { + parents.Push(node) + compareResult = bytes.Compare(key, node.key) + if compareResult < 0 { + node = node.left + continue + } + if compareResult > 0 { + node = node.right + continue + } + + // The key already exists, so update its value. + t.totalSize -= uint64(len(node.value)) + t.totalSize += uint64(len(value)) + node.value = value + return + } + + // Link the new node into the binary tree in the correct position. + node := newTreapNode(key, value, rand.Int()) + t.count++ + t.totalSize += nodeSize(node) + parent := parents.At(0) + if compareResult < 0 { + parent.left = node + } else { + parent.right = node + } + + // Perform any rotations needed to maintain the min-heap. + for parents.Len() > 0 { + // There is nothing left to do when the node's priority is + // greater than or equal to its parent's priority. + parent = parents.Pop() + if node.priority >= parent.priority { + break + } + + // Perform a right rotation if the node is on the left side or + // a left rotation if the node is on the right side. + if parent.left == node { + node.right, parent.left = parent, node.right + } else { + node.left, parent.right = parent, node.left + } + t.relinkGrandparent(node, parent, parents.At(0)) + } +} + +// Delete removes the passed key if it exists. +func (t *Mutable) Delete(key []byte) { + // Find the node for the key along with its parent. There is nothing to + // do if the key does not exist. + node, parent := t.get(key) + if node == nil { + return + } + + // When the only node in the tree is the root node and it is the one + // being deleted, there is nothing else to do besides removing it. + if parent == nil && node.left == nil && node.right == nil { + t.root = nil + t.count = 0 + t.totalSize = 0 + return + } + + // Perform rotations to move the node to delete to a leaf position while + // maintaining the min-heap. + var isLeft bool + var child *treapNode + for node.left != nil || node.right != nil { + // Choose the child with the higher priority. + if node.left == nil { + child = node.right + isLeft = false + } else if node.right == nil { + child = node.left + isLeft = true + } else if node.left.priority >= node.right.priority { + child = node.left + isLeft = true + } else { + child = node.right + isLeft = false + } + + // Rotate left or right depending on which side the child node + // is on. This has the effect of moving the node to delete + // towards the bottom of the tree while maintaining the + // min-heap. + if isLeft { + child.right, node.left = node, child.right + } else { + child.left, node.right = node, child.left + } + t.relinkGrandparent(child, node, parent) + + // The parent for the node to delete is now what was previously + // its child. + parent = child + } + + // Delete the node, which is now a leaf node, by disconnecting it from + // its parent. + if parent.right == node { + parent.right = nil + } else { + parent.left = nil + } + t.count-- + t.totalSize -= nodeSize(node) +} + +// ForEach invokes the passed function with every key/value pair in the treap +// in ascending order. +func (t *Mutable) ForEach(fn func(k, v []byte) bool) { + // Add the root node and all children to the left of it to the list of + // nodes to traverse and loop until they, and all of their child nodes, + // have been traversed. + var parents parentStack + for node := t.root; node != nil; node = node.left { + parents.Push(node) + } + for parents.Len() > 0 { + node := parents.Pop() + if !fn(node.key, node.value) { + return + } + + // Extend the nodes to traverse by all children to the left of + // the current node's right child. + for node := node.right; node != nil; node = node.left { + parents.Push(node) + } + } +} + +// Reset efficiently removes all items in the treap. +func (t *Mutable) Reset() { + t.count = 0 + t.totalSize = 0 + t.root = nil +} + +// NewMutable returns a new empty mutable treap ready for use. See the +// documentation for the Mutable structure for more details. +func NewMutable() *Mutable { + return &Mutable{} +} diff --git a/database/treap/mutable_test.go b/database/treap/mutable_test.go new file mode 100644 index 00000000000..ff479ec54e8 --- /dev/null +++ b/database/treap/mutable_test.go @@ -0,0 +1,465 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package treap + +import ( + "bytes" + "crypto/sha256" + "testing" +) + +// TestMutableEmpty ensures calling functions on an empty mutable treap works as +// expected. +func TestMutableEmpty(t *testing.T) { + t.Parallel() + + // Ensure the treap length is the expected value. + testTreap := NewMutable() + if gotLen := testTreap.Len(); gotLen != 0 { + t.Fatalf("Len: unexpected length - got %d, want %d", gotLen, 0) + } + + // Ensure the reported size is 0. + if gotSize := testTreap.Size(); gotSize != 0 { + t.Fatalf("Size: unexpected byte size - got %d, want 0", + gotSize) + } + + // Ensure there are no errors with requesting keys from an empty treap. + key := serializeUint32(0) + if gotVal := testTreap.Has(key); gotVal { + t.Fatalf("Has: unexpected result - got %v, want false", gotVal) + } + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get: unexpected result - got %x, want nil", gotVal) + } + + // Ensure there are no panics when deleting keys from an empty treap. + testTreap.Delete(key) + + // Ensure the number of keys iterated by ForEach on an empty treap is + // zero. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + numIterated++ + return true + }) + if numIterated != 0 { + t.Fatalf("ForEach: unexpected iterate count - got %d, want 0", + numIterated) + } +} + +// TestMutableReset ensures that resetting an existing mutable treap works as +// expected. +func TestMutableReset(t *testing.T) { + t.Parallel() + + // Insert a few keys. + numItems := 10 + testTreap := NewMutable() + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + testTreap.Put(key, key) + } + + // Reset it. + testTreap.Reset() + + // Ensure the treap length is now 0. + if gotLen := testTreap.Len(); gotLen != 0 { + t.Fatalf("Len: unexpected length - got %d, want %d", gotLen, 0) + } + + // Ensure the reported size is now 0. + if gotSize := testTreap.Size(); gotSize != 0 { + t.Fatalf("Size: unexpected byte size - got %d, want 0", + gotSize) + } + + // Ensure the treap no longer has any of the keys. + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + + // Ensure the treap no longer has the key. + if testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is in treap", i, key) + } + + // Get the key that no longer exists from the treap and ensure + // it is nil. + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get #%d: unexpected value - got %x, want nil", + i, gotVal) + } + } + + // Ensure the number of keys iterated by ForEach is zero. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + numIterated++ + return true + }) + if numIterated != 0 { + t.Fatalf("ForEach: unexpected iterate count - got %d, want 0", + numIterated) + } +} + +// TestMutableSequential ensures that putting keys into a mutable treap in +// sequential order works as expected. +func TestMutableSequential(t *testing.T) { + t.Parallel() + + // Insert a bunch of sequential keys while checking several of the treap + // functions work as expected. + expectedSize := uint64(0) + numItems := 1000 + testTreap := NewMutable() + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + testTreap.Put(key, key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != i+1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, i+1) + } + + // Ensure the treap has the key. + if !testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is not in treap", i, key) + } + + // Get the key from the treap and ensure it is the expected + // value. + if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) { + t.Fatalf("Get #%d: unexpected value - got %x, want %x", + i, gotVal, key) + } + + // Ensure the expected size is reported. + expectedSize += (nodeFieldsSize + 8) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } + + // Ensure the all keys are iterated by ForEach in order. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + wantKey := serializeUint32(uint32(numIterated)) + + // Ensure the key is as expected. + if !bytes.Equal(k, wantKey) { + t.Fatalf("ForEach #%d: unexpected key - got %x, want %x", + numIterated, k, wantKey) + } + + // Ensure the value is as expected. + if !bytes.Equal(v, wantKey) { + t.Fatalf("ForEach #%d: unexpected value - got %x, want %x", + numIterated, v, wantKey) + } + + numIterated++ + return true + }) + + // Ensure all items were iterated. + if numIterated != numItems { + t.Fatalf("ForEach: unexpected iterate count - got %d, want %d", + numIterated, numItems) + } + + // Delete the keys one-by-one while checking several of the treap + // functions work as expected. + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + testTreap.Delete(key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != numItems-i-1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, numItems-i-1) + } + + // Ensure the treap no longer has the key. + if testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is in treap", i, key) + } + + // Get the key that no longer exists from the treap and ensure + // it is nil. + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get #%d: unexpected value - got %x, want nil", + i, gotVal) + } + + // Ensure the expected size is reported. + expectedSize -= (nodeFieldsSize + 8) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } +} + +// TestMutableReverseSequential ensures that putting keys into a mutable treap +// in reverse sequential order works as expected. +func TestMutableReverseSequential(t *testing.T) { + t.Parallel() + + // Insert a bunch of sequential keys while checking several of the treap + // functions work as expected. + expectedSize := uint64(0) + numItems := 1000 + testTreap := NewMutable() + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(numItems - i - 1)) + testTreap.Put(key, key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != i+1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, i+1) + } + + // Ensure the treap has the key. + if !testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is not in treap", i, key) + } + + // Get the key from the treap and ensure it is the expected + // value. + if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) { + t.Fatalf("Get #%d: unexpected value - got %x, want %x", + i, gotVal, key) + } + + // Ensure the expected size is reported. + expectedSize += (nodeFieldsSize + 8) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } + + // Ensure the all keys are iterated by ForEach in order. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + wantKey := serializeUint32(uint32(numIterated)) + + // Ensure the key is as expected. + if !bytes.Equal(k, wantKey) { + t.Fatalf("ForEach #%d: unexpected key - got %x, want %x", + numIterated, k, wantKey) + } + + // Ensure the value is as expected. + if !bytes.Equal(v, wantKey) { + t.Fatalf("ForEach #%d: unexpected value - got %x, want %x", + numIterated, v, wantKey) + } + + numIterated++ + return true + }) + + // Ensure all items were iterated. + if numIterated != numItems { + t.Fatalf("ForEach: unexpected iterate count - got %d, want %d", + numIterated, numItems) + } + + // Delete the keys one-by-one while checking several of the treap + // functions work as expected. + for i := 0; i < numItems; i++ { + // Intentionally use the reverse order they were inserted here. + key := serializeUint32(uint32(i)) + testTreap.Delete(key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != numItems-i-1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, numItems-i-1) + } + + // Ensure the treap no longer has the key. + if testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is in treap", i, key) + } + + // Get the key that no longer exists from the treap and ensure + // it is nil. + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get #%d: unexpected value - got %x, want nil", + i, gotVal) + } + + // Ensure the expected size is reported. + expectedSize -= (nodeFieldsSize + 8) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } +} + +// TestMutableUnordered ensures that putting keys into a mutable treap in no +// paritcular order works as expected. +func TestMutableUnordered(t *testing.T) { + t.Parallel() + + // Insert a bunch of out-of-order keys while checking several of the + // treap functions work as expected. + expectedSize := uint64(0) + numItems := 1000 + testTreap := NewMutable() + for i := 0; i < numItems; i++ { + // Hash the serialized int to generate out-of-order keys. + hash := sha256.Sum256(serializeUint32(uint32(i))) + key := hash[:] + testTreap.Put(key, key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != i+1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, i+1) + } + + // Ensure the treap has the key. + if !testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is not in treap", i, key) + } + + // Get the key from the treap and ensure it is the expected + // value. + if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) { + t.Fatalf("Get #%d: unexpected value - got %x, want %x", + i, gotVal, key) + } + + // Ensure the expected size is reported. + expectedSize += nodeFieldsSize + uint64(len(key)+len(key)) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } + + // Delete the keys one-by-one while checking several of the treap + // functions work as expected. + for i := 0; i < numItems; i++ { + // Hash the serialized int to generate out-of-order keys. + hash := sha256.Sum256(serializeUint32(uint32(i))) + key := hash[:] + testTreap.Delete(key) + + // Ensure the treap length is the expected value. + if gotLen := testTreap.Len(); gotLen != numItems-i-1 { + t.Fatalf("Len #%d: unexpected length - got %d, want %d", + i, gotLen, numItems-i-1) + } + + // Ensure the treap no longer has the key. + if testTreap.Has(key) { + t.Fatalf("Has #%d: key %q is in treap", i, key) + } + + // Get the key that no longer exists from the treap and ensure + // it is nil. + if gotVal := testTreap.Get(key); gotVal != nil { + t.Fatalf("Get #%d: unexpected value - got %x, want nil", + i, gotVal) + } + + // Ensure the expected size is reported. + expectedSize -= (nodeFieldsSize + 64) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size #%d: unexpected byte size - got %d, "+ + "want %d", i, gotSize, expectedSize) + } + } +} + +// TestMutableDuplicatePut ensures that putting a duplicate key into a mutable +// treap updates the existing value. +func TestMutableDuplicatePut(t *testing.T) { + t.Parallel() + + key := serializeUint32(0) + val := []byte("testval") + + // Put the key twice with the second put being the expected final value. + testTreap := NewMutable() + testTreap.Put(key, key) + testTreap.Put(key, val) + + // Ensure the key still exists and is the new value. + if gotVal := testTreap.Has(key); !gotVal { + t.Fatalf("Has: unexpected result - got %v, want true", gotVal) + } + if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, val) { + t.Fatalf("Get: unexpected result - got %x, want %x", gotVal, val) + } + + // Ensure the expected size is reported. + expectedSize := uint64(nodeFieldsSize + len(key) + len(val)) + if gotSize := testTreap.Size(); gotSize != expectedSize { + t.Fatalf("Size: unexpected byte size - got %d, want %d", + gotSize, expectedSize) + } +} + +// TestMutableNilValue ensures that putting a nil value into a mutable treap +// results in a key being added with an empty byte slice. +func TestMutableNilValue(t *testing.T) { + t.Parallel() + + key := serializeUint32(0) + + // Put the key with a nil value. + testTreap := NewMutable() + testTreap.Put(key, nil) + + // Ensure the key exists and is an empty byte slice. + if gotVal := testTreap.Has(key); !gotVal { + t.Fatalf("Has: unexpected result - got %v, want true", gotVal) + } + if gotVal := testTreap.Get(key); gotVal == nil { + t.Fatalf("Get: unexpected result - got nil, want empty slice") + } + if gotVal := testTreap.Get(key); len(gotVal) != 0 { + t.Fatalf("Get: unexpected result - got %x, want empty slice", + gotVal) + } +} + +// TestMutableForEachStopIterator ensures that returning false from the ForEach +// callback of a mutable treap stops iteration early. +func TestMutableForEachStopIterator(t *testing.T) { + t.Parallel() + + // Insert a few keys. + numItems := 10 + testTreap := NewMutable() + for i := 0; i < numItems; i++ { + key := serializeUint32(uint32(i)) + testTreap.Put(key, key) + } + + // Ensure ForEach exits early on false return by caller. + var numIterated int + testTreap.ForEach(func(k, v []byte) bool { + numIterated++ + return numIterated != numItems/2 + }) + if numIterated != numItems/2 { + t.Fatalf("ForEach: unexpected iterate count - got %d, want %d", + numIterated, numItems/2) + } +} diff --git a/database/treap/treapiter.go b/database/treap/treapiter.go new file mode 100644 index 00000000000..ae7ed853b8e --- /dev/null +++ b/database/treap/treapiter.go @@ -0,0 +1,355 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package treap + +import "bytes" + +// Iterator represents an iterator for forwards and backwards iteration over +// the contents of a treap (mutable or immutable). +type Iterator struct { + t *Mutable // Mutable treap iterator is associated with or nil + root *treapNode // Root node of treap iterator is associated with + node *treapNode // The node the iterator is positioned at + parents parentStack // The stack of parents needed to iterate + isNew bool // Whether the iterator has been positioned + seekKey []byte // Used to handle dynamic updates for mutable treap + startKey []byte // Used to limit the iterator to a range + limitKey []byte // Used to limit the iterator to a range +} + +// limitIterator clears the current iterator node if it is outside of the range +// specified when the iterator was created. It returns whether the iterator is +// valid. +func (iter *Iterator) limitIterator() bool { + if iter.node == nil { + return false + } + + node := iter.node + if iter.startKey != nil && bytes.Compare(node.key, iter.startKey) < 0 { + iter.node = nil + return false + } + + if iter.limitKey != nil && bytes.Compare(node.key, iter.limitKey) >= 0 { + iter.node = nil + return false + } + + return true +} + +// seek moves the iterator based on the provided key and flags. +// +// When the exact match flag is set, the iterator will either be moved to first +// key in the treap that exactly matches the provided key, or the one +// before/after it depending on the greater flag. +// +// When the exact match flag is NOT set, the iterator will be moved to the first +// key in the treap before/after the provided key depending on the greater flag. +// +// In all cases, the limits specified when the iterator was created are +// respected. +func (iter *Iterator) seek(key []byte, exactMatch bool, greater bool) bool { + iter.node = nil + iter.parents = parentStack{} + var selectedNodeDepth int + for node := iter.root; node != nil; { + iter.parents.Push(node) + + // Traverse left or right depending on the result of the + // comparison. Also, set the iterator to the node depending on + // the flags so the iterator is positioned properly when an + // exact match isn't found. + compareResult := bytes.Compare(key, node.key) + if compareResult < 0 { + if greater { + iter.node = node + selectedNodeDepth = iter.parents.Len() - 1 + } + node = node.left + continue + } + if compareResult > 0 { + if !greater { + iter.node = node + selectedNodeDepth = iter.parents.Len() - 1 + } + node = node.right + continue + } + + // The key is an exact match. Set the iterator and return now + // when the exact match flag is set. + if exactMatch { + iter.node = node + iter.parents.Pop() + return iter.limitIterator() + } + + // The key is an exact match, but the exact match is not set, so + // choose which direction to go based on whether the larger or + // smaller key was requested. + if greater { + node = node.right + } else { + node = node.left + } + } + + // There was either no exact match or there was an exact match but the + // exact match flag was not set. In any case, the parent stack might + // need to be adjusted to only include the parents up to the selected + // node. Also, ensure the selected node's key does not exceed the + // allowed range of the iterator. + for i := iter.parents.Len(); i > selectedNodeDepth; i-- { + iter.parents.Pop() + } + return iter.limitIterator() +} + +// First moves the iterator to the first key/value pair. When there is only a +// single key/value pair both First and Last will point to the same pair. +// Returns false if there are no key/value pairs. +func (iter *Iterator) First() bool { + // Seek the start key if the iterator was created with one. This will + // result in either an exact match, the first greater key, or an + // exhausted iterator if no such key exists. + iter.isNew = false + if iter.startKey != nil { + return iter.seek(iter.startKey, true, true) + } + + // The smallest key is in the left-most node. + iter.parents = parentStack{} + for node := iter.root; node != nil; node = node.left { + if node.left == nil { + iter.node = node + return true + } + iter.parents.Push(node) + } + return false +} + +// Last moves the iterator to the last key/value pair. When there is only a +// single key/value pair both First and Last will point to the same pair. +// Returns false if there are no key/value pairs. +func (iter *Iterator) Last() bool { + // Seek the limit key if the iterator was created with one. This will + // result in the first key smaller than the limit key, or an exhausted + // iterator if no such key exists. + iter.isNew = false + if iter.limitKey != nil { + return iter.seek(iter.limitKey, false, false) + } + + // The highest key is in the right-most node. + iter.parents = parentStack{} + for node := iter.root; node != nil; node = node.right { + if node.right == nil { + iter.node = node + return true + } + iter.parents.Push(node) + } + return false +} + +// Next moves the iterator to the next key/value pair and returns false when the +// iterator is exhausted. When invoked on a newly created iterator it will +// position the iterator at the first item. +func (iter *Iterator) Next() bool { + if iter.isNew { + return iter.First() + } + + if iter.node == nil { + return false + } + + // Reseek the previous key without allowing for an exact match if a + // force seek was requested. This results in the key greater than the + // previous one or an exhausted iterator if there is no such key. + if seekKey := iter.seekKey; seekKey != nil { + iter.seekKey = nil + return iter.seek(seekKey, false, true) + } + + // When there is no right node walk the parents until the parent's right + // node is not equal to the previous child. This will be the next node. + if iter.node.right == nil { + parent := iter.parents.Pop() + for parent != nil && parent.right == iter.node { + iter.node = parent + parent = iter.parents.Pop() + } + iter.node = parent + return iter.limitIterator() + } + + // There is a right node, so the next node is the left-most node down + // the right sub-tree. + iter.parents.Push(iter.node) + iter.node = iter.node.right + for node := iter.node.left; node != nil; node = node.left { + iter.parents.Push(iter.node) + iter.node = node + } + return iter.limitIterator() +} + +// Prev moves the iterator to the previous key/value pair and returns false when +// the iterator is exhausted. When invoked on a newly created iterator it will +// position the iterator at the last item. +func (iter *Iterator) Prev() bool { + if iter.isNew { + return iter.Last() + } + + if iter.node == nil { + return false + } + + // Reseek the previous key without allowing for an exact match if a + // force seek was requested. This results in the key smaller than the + // previous one or an exhausted iterator if there is no such key. + if seekKey := iter.seekKey; seekKey != nil { + iter.seekKey = nil + return iter.seek(seekKey, false, false) + } + + // When there is no left node walk the parents until the parent's left + // node is not equal to the previous child. This will be the previous + // node. + for iter.node.left == nil { + parent := iter.parents.Pop() + for parent != nil && parent.left == iter.node { + iter.node = parent + parent = iter.parents.Pop() + } + iter.node = parent + return iter.limitIterator() + } + + // There is a left node, so the previous node is the right-most node + // down the left sub-tree. + iter.parents.Push(iter.node) + iter.node = iter.node.left + for node := iter.node.right; node != nil; node = node.right { + iter.parents.Push(iter.node) + iter.node = node + } + return iter.limitIterator() +} + +// Seek moves the iterator to the first key/value pair with a key that is +// greater than or equal to the given key and returns true if successful. +func (iter *Iterator) Seek(key []byte) bool { + iter.isNew = false + return iter.seek(key, true, true) +} + +// Key returns the key of the current key/value pair or nil when the iterator +// is exhausted. The caller should not modify the contents of the returned +// slice. +func (iter *Iterator) Key() []byte { + if iter.node == nil { + return nil + } + return iter.node.key +} + +// Value returns the value of the current key/value pair or nil when the +// iterator is exhausted. The caller should not modify the contents of the +// returned slice. +func (iter *Iterator) Value() []byte { + if iter.node == nil { + return nil + } + return iter.node.value +} + +// Valid indicates whether the iterator is positioned at a valid key/value pair. +// It will be considered invalid when the iterator is newly created or exhausted. +func (iter *Iterator) Valid() bool { + return iter.node != nil +} + +// ForceReseek notifies the iterator that the underlying mutable treap has been +// updated, so the next call to Prev or Next needs to reseek in order to allow +// the iterator to continue working properly. +// +// NOTE: Calling this function when the iterator is associated with an immutable +// treap has no effect as you would expect. +func (iter *Iterator) ForceReseek() { + // Nothing to do when the iterator is associated with an immutable + // treap. + if iter.t == nil { + return + } + + // Update the iterator root to the mutable treap root in case it + // changed. + iter.root = iter.t.root + + // Set the seek key to the current node. This will force the Next/Prev + // functions to reseek, and thus properly reconstruct the iterator, on + // their next call. + if iter.node == nil { + iter.seekKey = nil + return + } + iter.seekKey = iter.node.key +} + +// Iterator returns a new iterator for the mutable treap. The newly returned +// iterator is not pointing to a valid item until a call to one of the methods +// to position it is made. +// +// The start key and limit key parameters cause the iterator to be limited to +// a range of keys. The start key is inclusive and the limit key is exclusive. +// Either or both can be nil if the functionality is not desired. +// +// WARNING: The ForceSeek method must be called on the returned iterator if +// the treap is mutated. Failure to do so will cause the iterator to return +// unexpected keys and/or values. +// +// For example: +// +// iter := t.Iterator(nil, nil) +// for iter.Next() { +// if someCondition { +// t.Delete(iter.Key()) +// iter.ForceReseek() +// } +// } +func (t *Mutable) Iterator(startKey, limitKey []byte) *Iterator { + iter := &Iterator{ + t: t, + root: t.root, + isNew: true, + startKey: startKey, + limitKey: limitKey, + } + return iter +} + +// Iterator returns a new iterator for the immutable treap. The newly returned +// iterator is not pointing to a valid item until a call to one of the methods +// to position it is made. +// +// The start key and limit key parameters cause the iterator to be limited to +// a range of keys. The start key is inclusive and the limit key is exclusive. +// Either or both can be nil if the functionality is not desired. +func (t *Immutable) Iterator(startKey, limitKey []byte) *Iterator { + iter := &Iterator{ + root: t.root, + isNew: true, + startKey: startKey, + limitKey: limitKey, + } + return iter +} diff --git a/database/treap/treapiter_test.go b/database/treap/treapiter_test.go new file mode 100644 index 00000000000..08b4335ebc9 --- /dev/null +++ b/database/treap/treapiter_test.go @@ -0,0 +1,719 @@ +// Copyright (c) 2015-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package treap + +import ( + "bytes" + "encoding/binary" + "testing" +) + +// TestMutableIterator ensures that the general behavior of mutable treap +// iterators is as expected including tests for first, last, ordered and reverse +// ordered iteration, limiting the range, seeking, and initially unpositioned. +func TestMutableIterator(t *testing.T) { + t.Parallel() + + tests := []struct { + numKeys int + step int + startKey []byte + limitKey []byte + expectedFirst []byte + expectedLast []byte + seekKey []byte + expectedSeek []byte + }{ + // No range limits. Values are the set (0, 1, 2, ..., 49). + // Seek existing value. + { + numKeys: 50, + step: 1, + expectedFirst: serializeUint32(0), + expectedLast: serializeUint32(49), + seekKey: serializeUint32(12), + expectedSeek: serializeUint32(12), + }, + + // Limited to range [24, end]. Values are the set + // (0, 2, 4, ..., 48). Seek value that doesn't exist and is + // greater than largest existing key. + { + numKeys: 50, + step: 2, + startKey: serializeUint32(24), + expectedFirst: serializeUint32(24), + expectedLast: serializeUint32(48), + seekKey: serializeUint32(49), + expectedSeek: nil, + }, + + // Limited to range [start, 25). Values are the set + // (0, 3, 6, ..., 48). Seek value that doesn't exist but is + // before an existing value within the range. + { + numKeys: 50, + step: 3, + limitKey: serializeUint32(25), + expectedFirst: serializeUint32(0), + expectedLast: serializeUint32(24), + seekKey: serializeUint32(17), + expectedSeek: serializeUint32(18), + }, + + // Limited to range [10, 21). Values are the set + // (0, 4, ..., 48). Seek value that exists, but is before the + // minimum allowed range. + { + numKeys: 50, + step: 4, + startKey: serializeUint32(10), + limitKey: serializeUint32(21), + expectedFirst: serializeUint32(12), + expectedLast: serializeUint32(20), + seekKey: serializeUint32(4), + expectedSeek: nil, + }, + + // Limited by prefix {0,0,0}, range [{0,0,0}, {0,0,1}). + // Since it's a bytewise compare, {0,0,0,...} < {0,0,1}. + // Seek existing value within the allowed range. + { + numKeys: 300, + step: 1, + startKey: []byte{0x00, 0x00, 0x00}, + limitKey: []byte{0x00, 0x00, 0x01}, + expectedFirst: serializeUint32(0), + expectedLast: serializeUint32(255), + seekKey: serializeUint32(100), + expectedSeek: serializeUint32(100), + }, + } + +testLoop: + for i, test := range tests { + // Insert a bunch of keys. + testTreap := NewMutable() + for i := 0; i < test.numKeys; i += test.step { + key := serializeUint32(uint32(i)) + testTreap.Put(key, key) + } + + // Create new iterator limited by the test params. + iter := testTreap.Iterator(test.startKey, test.limitKey) + + // Ensure the first item is accurate. + hasFirst := iter.First() + if !hasFirst && test.expectedFirst != nil { + t.Errorf("First #%d: unexpected exhausted iterator", i) + continue + } + gotKey := iter.Key() + if !bytes.Equal(gotKey, test.expectedFirst) { + t.Errorf("First.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedFirst) + continue + } + gotVal := iter.Value() + if !bytes.Equal(gotVal, test.expectedFirst) { + t.Errorf("First.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedFirst) + continue + } + + // Ensure the iterator gives the expected items in order. + curNum := binary.BigEndian.Uint32(test.expectedFirst) + for iter.Next() { + curNum += uint32(test.step) + + // Ensure key is as expected. + gotKey := iter.Key() + expectedKey := serializeUint32(curNum) + if !bytes.Equal(gotKey, expectedKey) { + t.Errorf("iter.Key #%d (%d): unexpected key - "+ + "got %x, want %x", i, curNum, gotKey, + expectedKey) + continue testLoop + } + + // Ensure value is as expected. + gotVal := iter.Value() + if !bytes.Equal(gotVal, expectedKey) { + t.Errorf("iter.Value #%d (%d): unexpected "+ + "value - got %x, want %x", i, curNum, + gotVal, expectedKey) + continue testLoop + } + } + + // Ensure iterator is exhausted. + if iter.Valid() { + t.Errorf("Valid #%d: iterator should be exhausted", i) + continue + } + + // Ensure the last item is accurate. + hasLast := iter.Last() + if !hasLast && test.expectedLast != nil { + t.Errorf("Last #%d: unexpected exhausted iterator", i) + continue + } + gotKey = iter.Key() + if !bytes.Equal(gotKey, test.expectedLast) { + t.Errorf("Last.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedLast) + continue + } + gotVal = iter.Value() + if !bytes.Equal(gotVal, test.expectedLast) { + t.Errorf("Last.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedLast) + continue + } + + // Ensure the iterator gives the expected items in reverse + // order. + curNum = binary.BigEndian.Uint32(test.expectedLast) + for iter.Prev() { + curNum -= uint32(test.step) + + // Ensure key is as expected. + gotKey := iter.Key() + expectedKey := serializeUint32(curNum) + if !bytes.Equal(gotKey, expectedKey) { + t.Errorf("iter.Key #%d (%d): unexpected key - "+ + "got %x, want %x", i, curNum, gotKey, + expectedKey) + continue testLoop + } + + // Ensure value is as expected. + gotVal := iter.Value() + if !bytes.Equal(gotVal, expectedKey) { + t.Errorf("iter.Value #%d (%d): unexpected "+ + "value - got %x, want %x", i, curNum, + gotVal, expectedKey) + continue testLoop + } + } + + // Ensure iterator is exhausted. + if iter.Valid() { + t.Errorf("Valid #%d: iterator should be exhausted", i) + continue + } + + // Seek to the provided key. + seekValid := iter.Seek(test.seekKey) + if !seekValid && test.expectedSeek != nil { + t.Errorf("Seek #%d: unexpected exhausted iterator", i) + continue + } + gotKey = iter.Key() + if !bytes.Equal(gotKey, test.expectedSeek) { + t.Errorf("Seek.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedSeek) + continue + } + gotVal = iter.Value() + if !bytes.Equal(gotVal, test.expectedSeek) { + t.Errorf("Seek.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedSeek) + continue + } + + // Recreate the iterator and ensure calling Next on it before it + // has been positioned gives the first element. + iter = testTreap.Iterator(test.startKey, test.limitKey) + hasNext := iter.Next() + if !hasNext && test.expectedFirst != nil { + t.Errorf("Next #%d: unexpected exhausted iterator", i) + continue + } + gotKey = iter.Key() + if !bytes.Equal(gotKey, test.expectedFirst) { + t.Errorf("Next.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedFirst) + continue + } + gotVal = iter.Value() + if !bytes.Equal(gotVal, test.expectedFirst) { + t.Errorf("Next.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedFirst) + continue + } + + // Recreate the iterator and ensure calling Prev on it before it + // has been positioned gives the first element. + iter = testTreap.Iterator(test.startKey, test.limitKey) + hasPrev := iter.Prev() + if !hasPrev && test.expectedLast != nil { + t.Errorf("Prev #%d: unexpected exhausted iterator", i) + continue + } + gotKey = iter.Key() + if !bytes.Equal(gotKey, test.expectedLast) { + t.Errorf("Prev.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedLast) + continue + } + gotVal = iter.Value() + if !bytes.Equal(gotVal, test.expectedLast) { + t.Errorf("Next.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedLast) + continue + } + } +} + +// TestMutableEmptyIterator ensures that the various functions behave as +// expected when a mutable treap is empty. +func TestMutableEmptyIterator(t *testing.T) { + t.Parallel() + + // Create iterator against empty treap. + testTreap := NewMutable() + iter := testTreap.Iterator(nil, nil) + + // Ensure Valid on empty iterator reports it as exhausted. + if iter.Valid() { + t.Fatal("Valid: iterator should be exhausted") + } + + // Ensure First and Last on empty iterator report it as exhausted. + if iter.First() { + t.Fatal("First: iterator should be exhausted") + } + if iter.Last() { + t.Fatal("Last: iterator should be exhausted") + } + + // Ensure Next and Prev on empty iterator report it as exhausted. + if iter.Next() { + t.Fatal("Next: iterator should be exhausted") + } + if iter.Prev() { + t.Fatal("Prev: iterator should be exhausted") + } + + // Ensure Key and Value on empty iterator are nil. + if gotKey := iter.Key(); gotKey != nil { + t.Fatalf("Key: should be nil - got %q", gotKey) + } + if gotVal := iter.Value(); gotVal != nil { + t.Fatalf("Value: should be nil - got %q", gotVal) + } + + // Ensure Next and Prev report exhausted after forcing a reseek on an + // empty iterator. + iter.ForceReseek() + if iter.Next() { + t.Fatal("Next: iterator should be exhausted") + } + iter.ForceReseek() + if iter.Prev() { + t.Fatal("Prev: iterator should be exhausted") + } +} + +// TestIteratorUpdates ensures that issuing a call to ForceReseek on an iterator +// that had the underlying mutable treap updated works as expected. +func TestIteratorUpdates(t *testing.T) { + t.Parallel() + + // Create a new treap with various values inserted in no particular + // order. The resulting keys are the set (2, 4, 7, 11, 18, 25). + testTreap := NewMutable() + testTreap.Put(serializeUint32(7), nil) + testTreap.Put(serializeUint32(2), nil) + testTreap.Put(serializeUint32(18), nil) + testTreap.Put(serializeUint32(11), nil) + testTreap.Put(serializeUint32(25), nil) + testTreap.Put(serializeUint32(4), nil) + + // Create an iterator against the treap with a range that excludes the + // lowest and highest entries. The limited set is then (4, 7, 11, 18) + iter := testTreap.Iterator(serializeUint32(3), serializeUint32(25)) + + // Delete a key from the middle of the range and notify the iterator to + // force a reseek. + testTreap.Delete(serializeUint32(11)) + iter.ForceReseek() + + // Ensure that calling Next on the iterator after the forced reseek + // gives the expected key. The limited set of keys at this point is + // (4, 7, 18) and the iterator has not yet been positioned. + if !iter.Next() { + t.Fatal("ForceReseek.Next: unexpected exhausted iterator") + } + wantKey := serializeUint32(4) + gotKey := iter.Key() + if !bytes.Equal(gotKey, wantKey) { + t.Fatalf("ForceReseek.Key: unexpected key - got %x, want %x", + gotKey, wantKey) + } + + // Delete the key the iterator is currently position at and notify the + // iterator to force a reseek. + testTreap.Delete(serializeUint32(4)) + iter.ForceReseek() + + // Ensure that calling Next on the iterator after the forced reseek + // gives the expected key. The limited set of keys at this point is + // (7, 18) and the iterator is positioned at a deleted entry before 7. + if !iter.Next() { + t.Fatal("ForceReseek.Next: unexpected exhausted iterator") + } + wantKey = serializeUint32(7) + gotKey = iter.Key() + if !bytes.Equal(gotKey, wantKey) { + t.Fatalf("ForceReseek.Key: unexpected key - got %x, want %x", + gotKey, wantKey) + } + + // Add a key before the current key the iterator is position at and + // notify the iterator to force a reseek. + testTreap.Put(serializeUint32(4), nil) + iter.ForceReseek() + + // Ensure that calling Prev on the iterator after the forced reseek + // gives the expected key. The limited set of keys at this point is + // (4, 7, 18) and the iterator is positioned at 7. + if !iter.Prev() { + t.Fatal("ForceReseek.Prev: unexpected exhausted iterator") + } + wantKey = serializeUint32(4) + gotKey = iter.Key() + if !bytes.Equal(gotKey, wantKey) { + t.Fatalf("ForceReseek.Key: unexpected key - got %x, want %x", + gotKey, wantKey) + } + + // Delete the next key the iterator would ordinarily move to then notify + // the iterator to force a reseek. + testTreap.Delete(serializeUint32(7)) + iter.ForceReseek() + + // Ensure that calling Next on the iterator after the forced reseek + // gives the expected key. The limited set of keys at this point is + // (4, 18) and the iterator is positioned at 4. + if !iter.Next() { + t.Fatal("ForceReseek.Next: unexpected exhausted iterator") + } + wantKey = serializeUint32(18) + gotKey = iter.Key() + if !bytes.Equal(gotKey, wantKey) { + t.Fatalf("ForceReseek.Key: unexpected key - got %x, want %x", + gotKey, wantKey) + } +} + +// TestImmutableIterator ensures that the general behavior of immutable treap +// iterators is as expected including tests for first, last, ordered and reverse +// ordered iteration, limiting the range, seeking, and initially unpositioned. +func TestImmutableIterator(t *testing.T) { + t.Parallel() + + tests := []struct { + numKeys int + step int + startKey []byte + limitKey []byte + expectedFirst []byte + expectedLast []byte + seekKey []byte + expectedSeek []byte + }{ + // No range limits. Values are the set (0, 1, 2, ..., 49). + // Seek existing value. + { + numKeys: 50, + step: 1, + expectedFirst: serializeUint32(0), + expectedLast: serializeUint32(49), + seekKey: serializeUint32(12), + expectedSeek: serializeUint32(12), + }, + + // Limited to range [24, end]. Values are the set + // (0, 2, 4, ..., 48). Seek value that doesn't exist and is + // greater than largest existing key. + { + numKeys: 50, + step: 2, + startKey: serializeUint32(24), + expectedFirst: serializeUint32(24), + expectedLast: serializeUint32(48), + seekKey: serializeUint32(49), + expectedSeek: nil, + }, + + // Limited to range [start, 25). Values are the set + // (0, 3, 6, ..., 48). Seek value that doesn't exist but is + // before an existing value within the range. + { + numKeys: 50, + step: 3, + limitKey: serializeUint32(25), + expectedFirst: serializeUint32(0), + expectedLast: serializeUint32(24), + seekKey: serializeUint32(17), + expectedSeek: serializeUint32(18), + }, + + // Limited to range [10, 21). Values are the set + // (0, 4, ..., 48). Seek value that exists, but is before the + // minimum allowed range. + { + numKeys: 50, + step: 4, + startKey: serializeUint32(10), + limitKey: serializeUint32(21), + expectedFirst: serializeUint32(12), + expectedLast: serializeUint32(20), + seekKey: serializeUint32(4), + expectedSeek: nil, + }, + + // Limited by prefix {0,0,0}, range [{0,0,0}, {0,0,1}). + // Since it's a bytewise compare, {0,0,0,...} < {0,0,1}. + // Seek existing value within the allowed range. + { + numKeys: 300, + step: 1, + startKey: []byte{0x00, 0x00, 0x00}, + limitKey: []byte{0x00, 0x00, 0x01}, + expectedFirst: serializeUint32(0), + expectedLast: serializeUint32(255), + seekKey: serializeUint32(100), + expectedSeek: serializeUint32(100), + }, + } + +testLoop: + for i, test := range tests { + // Insert a bunch of keys. + testTreap := NewImmutable() + for i := 0; i < test.numKeys; i += test.step { + key := serializeUint32(uint32(i)) + testTreap = testTreap.Put(key, key) + } + + // Create new iterator limited by the test params. + iter := testTreap.Iterator(test.startKey, test.limitKey) + + // Ensure the first item is accurate. + hasFirst := iter.First() + if !hasFirst && test.expectedFirst != nil { + t.Errorf("First #%d: unexpected exhausted iterator", i) + continue + } + gotKey := iter.Key() + if !bytes.Equal(gotKey, test.expectedFirst) { + t.Errorf("First.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedFirst) + continue + } + gotVal := iter.Value() + if !bytes.Equal(gotVal, test.expectedFirst) { + t.Errorf("First.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedFirst) + continue + } + + // Ensure the iterator gives the expected items in order. + curNum := binary.BigEndian.Uint32(test.expectedFirst) + for iter.Next() { + curNum += uint32(test.step) + + // Ensure key is as expected. + gotKey := iter.Key() + expectedKey := serializeUint32(curNum) + if !bytes.Equal(gotKey, expectedKey) { + t.Errorf("iter.Key #%d (%d): unexpected key - "+ + "got %x, want %x", i, curNum, gotKey, + expectedKey) + continue testLoop + } + + // Ensure value is as expected. + gotVal := iter.Value() + if !bytes.Equal(gotVal, expectedKey) { + t.Errorf("iter.Value #%d (%d): unexpected "+ + "value - got %x, want %x", i, curNum, + gotVal, expectedKey) + continue testLoop + } + } + + // Ensure iterator is exhausted. + if iter.Valid() { + t.Errorf("Valid #%d: iterator should be exhausted", i) + continue + } + + // Ensure the last item is accurate. + hasLast := iter.Last() + if !hasLast && test.expectedLast != nil { + t.Errorf("Last #%d: unexpected exhausted iterator", i) + continue + } + gotKey = iter.Key() + if !bytes.Equal(gotKey, test.expectedLast) { + t.Errorf("Last.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedLast) + continue + } + gotVal = iter.Value() + if !bytes.Equal(gotVal, test.expectedLast) { + t.Errorf("Last.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedLast) + continue + } + + // Ensure the iterator gives the expected items in reverse + // order. + curNum = binary.BigEndian.Uint32(test.expectedLast) + for iter.Prev() { + curNum -= uint32(test.step) + + // Ensure key is as expected. + gotKey := iter.Key() + expectedKey := serializeUint32(curNum) + if !bytes.Equal(gotKey, expectedKey) { + t.Errorf("iter.Key #%d (%d): unexpected key - "+ + "got %x, want %x", i, curNum, gotKey, + expectedKey) + continue testLoop + } + + // Ensure value is as expected. + gotVal := iter.Value() + if !bytes.Equal(gotVal, expectedKey) { + t.Errorf("iter.Value #%d (%d): unexpected "+ + "value - got %x, want %x", i, curNum, + gotVal, expectedKey) + continue testLoop + } + } + + // Ensure iterator is exhausted. + if iter.Valid() { + t.Errorf("Valid #%d: iterator should be exhausted", i) + continue + } + + // Seek to the provided key. + seekValid := iter.Seek(test.seekKey) + if !seekValid && test.expectedSeek != nil { + t.Errorf("Seek #%d: unexpected exhausted iterator", i) + continue + } + gotKey = iter.Key() + if !bytes.Equal(gotKey, test.expectedSeek) { + t.Errorf("Seek.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedSeek) + continue + } + gotVal = iter.Value() + if !bytes.Equal(gotVal, test.expectedSeek) { + t.Errorf("Seek.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedSeek) + continue + } + + // Recreate the iterator and ensure calling Next on it before it + // has been positioned gives the first element. + iter = testTreap.Iterator(test.startKey, test.limitKey) + hasNext := iter.Next() + if !hasNext && test.expectedFirst != nil { + t.Errorf("Next #%d: unexpected exhausted iterator", i) + continue + } + gotKey = iter.Key() + if !bytes.Equal(gotKey, test.expectedFirst) { + t.Errorf("Next.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedFirst) + continue + } + gotVal = iter.Value() + if !bytes.Equal(gotVal, test.expectedFirst) { + t.Errorf("Next.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedFirst) + continue + } + + // Recreate the iterator and ensure calling Prev on it before it + // has been positioned gives the first element. + iter = testTreap.Iterator(test.startKey, test.limitKey) + hasPrev := iter.Prev() + if !hasPrev && test.expectedLast != nil { + t.Errorf("Prev #%d: unexpected exhausted iterator", i) + continue + } + gotKey = iter.Key() + if !bytes.Equal(gotKey, test.expectedLast) { + t.Errorf("Prev.Key #%d: unexpected key - got %x, "+ + "want %x", i, gotKey, test.expectedLast) + continue + } + gotVal = iter.Value() + if !bytes.Equal(gotVal, test.expectedLast) { + t.Errorf("Next.Value #%d: unexpected value - got %x, "+ + "want %x", i, gotVal, test.expectedLast) + continue + } + } +} + +// TestImmutableEmptyIterator ensures that the various functions behave as +// expected when an immutable treap is empty. +func TestImmutableEmptyIterator(t *testing.T) { + t.Parallel() + + // Create iterator against empty treap. + testTreap := NewImmutable() + iter := testTreap.Iterator(nil, nil) + + // Ensure Valid on empty iterator reports it as exhausted. + if iter.Valid() { + t.Fatal("Valid: iterator should be exhausted") + } + + // Ensure First and Last on empty iterator report it as exhausted. + if iter.First() { + t.Fatal("First: iterator should be exhausted") + } + if iter.Last() { + t.Fatal("Last: iterator should be exhausted") + } + + // Ensure Next and Prev on empty iterator report it as exhausted. + if iter.Next() { + t.Fatal("Next: iterator should be exhausted") + } + if iter.Prev() { + t.Fatal("Prev: iterator should be exhausted") + } + + // Ensure Key and Value on empty iterator are nil. + if gotKey := iter.Key(); gotKey != nil { + t.Fatalf("Key: should be nil - got %q", gotKey) + } + if gotVal := iter.Value(); gotVal != nil { + t.Fatalf("Value: should be nil - got %q", gotVal) + } + + // Ensure calling ForceReseek on an immutable treap iterator does not + // cause any issues since it only applies to mutable treap iterators. + iter.ForceReseek() + if iter.Next() { + t.Fatal("Next: iterator should be exhausted") + } + iter.ForceReseek() + if iter.Prev() { + t.Fatal("Prev: iterator should be exhausted") + } +} diff --git a/go.mod b/go.mod index 4a05d30857a..d9907b168d6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,7 @@ -module github.com/btcsuite/btcd +module github.com/peercoin/ppcd require ( + github.com/btcsuite/btcd v0.23.4 github.com/btcsuite/btcd/btcec/v2 v2.1.3 github.com/btcsuite/btcd/btcutil v1.1.0 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 @@ -11,26 +12,33 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 github.com/decred/dcrd/lru v1.0.0 + github.com/gorilla/websocket v1.5.1 github.com/jessevdk/go-flags v1.4.0 github.com/jrick/logrotate v1.0.0 github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed + golang.org/x/crypto v0.14.0 + golang.org/x/sys v0.13.0 ) require ( github.com/aead/siphash v1.0.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/gorilla/websocket v1.5.0 // indirect github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/net v0.17.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) replace github.com/btcsuite/btcd/btcutil => ./btcutil +replace github.com/btcsuite/btcd/btcjson => ./btcjson + +replace github.com/btcsuite/btcd/database/ffldb => ./database/ffldb + +replace github.com/btcsuite/btcd => ./ + // The retract statements below fixes an accidental push of the tags of a btcd // fork. retract ( @@ -63,4 +71,4 @@ retract ( v0.13.0-beta ) -go 1.17 +go 1.21.4 diff --git a/go.sum b/go.sum index e77dfa2f5f5..6321ea3dda3 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ 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.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= @@ -38,8 +36,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW 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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -64,13 +62,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -80,12 +80,14 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/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-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/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 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/integration/bip0009_test.go b/integration/bip0009_test.go deleted file mode 100644 index 5b644804108..00000000000 --- a/integration/bip0009_test.go +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright (c) 2016 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -// This file is ignored during the regular tests due to the following build tag. -//go:build rpctest -// +build rpctest - -package integration - -import ( - "fmt" - "runtime" - "testing" - "time" - - "github.com/btcsuite/btcd/blockchain" - "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/integration/rpctest" -) - -const ( - // vbLegacyBlockVersion is the highest legacy block version before the - // version bits scheme became active. - vbLegacyBlockVersion = 4 - - // vbTopBits defines the bits to set in the version to signal that the - // version bits scheme is being used. - vbTopBits = 0x20000000 -) - -// assertVersionBit gets the passed block hash from the given test harness and -// ensures its version either has the provided bit set or unset per the set -// flag. -func assertVersionBit(r *rpctest.Harness, t *testing.T, hash *chainhash.Hash, bit uint8, set bool) { - block, err := r.Client.GetBlock(hash) - if err != nil { - t.Fatalf("failed to retrieve block %v: %v", hash, err) - } - switch { - case set && block.Header.Version&(1< uint32(len(r.ActiveNet.Deployments)) { - t.Fatalf("deployment ID %d does not exist", deploymentID) - } - deployment := &r.ActiveNet.Deployments[deploymentID] - activationThreshold := r.ActiveNet.RuleChangeActivationThreshold - if deployment.CustomActivationThreshold != 0 { - activationThreshold = deployment.CustomActivationThreshold - } - signalForkVersion := int32(1<= 0 { - t.Fatal("transaction was accepted into the mempool " + - "but should be rejected!") - } else if err != nil && !strings.Contains(err.Error(), "not finalized") { - t.Fatalf("transaction should be rejected from mempool "+ - "due to being non-final, instead: %v", err) - } - - txns = []*btcutil.Tx{btcutil.NewTx(tx)} - _, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{}) - if err == nil && timeLockDelta >= 0 { - t.Fatal("block should be rejected due to non-final " + - "txn, but was accepted") - } else if err != nil && !strings.Contains(err.Error(), "unfinalized") { - t.Fatalf("block should be rejected due to non-final "+ - "tx, instead: %v", err) - } - } -} - -// createCSVOutput creates an output paying to a trivially redeemable CSV -// pkScript with the specified time-lock. -func createCSVOutput(r *rpctest.Harness, t *testing.T, - numSatoshis btcutil.Amount, timeLock int32, - isSeconds bool) ([]byte, *wire.OutPoint, *wire.MsgTx, error) { - - // Convert the time-lock to the proper sequence lock based according to - // if the lock is seconds or time based. - sequenceLock := blockchain.LockTimeToSequence(isSeconds, - uint32(timeLock)) - - // Our CSV script is simply: OP_CSV OP_DROP - b := txscript.NewScriptBuilder(). - AddInt64(int64(sequenceLock)). - AddOp(txscript.OP_CHECKSEQUENCEVERIFY). - AddOp(txscript.OP_DROP) - csvScript, err := b.Script() - if err != nil { - return nil, nil, nil, err - } - - // Using the script generated above, create a P2SH output which will be - // accepted into the mempool. - p2shAddr, err := btcutil.NewAddressScriptHash(csvScript, r.ActiveNet) - if err != nil { - return nil, nil, nil, err - } - p2shScript, err := txscript.PayToAddrScript(p2shAddr) - if err != nil { - return nil, nil, nil, err - } - output := &wire.TxOut{ - PkScript: p2shScript, - Value: int64(numSatoshis), - } - - // Finally create a valid transaction which creates the output crafted - // above. - tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) - if err != nil { - return nil, nil, nil, err - } - - var outputIndex uint32 - if !bytes.Equal(tx.TxOut[0].PkScript, p2shScript) { - outputIndex = 1 - } - - utxo := &wire.OutPoint{ - Hash: tx.TxHash(), - Index: outputIndex, - } - - return csvScript, utxo, tx, nil -} - -// spendCSVOutput spends an output previously created by the createCSVOutput -// function. The sigScript is a trivial push of OP_TRUE followed by the -// redeemScript to pass P2SH evaluation. -func spendCSVOutput(redeemScript []byte, csvUTXO *wire.OutPoint, - sequence uint32, targetOutput *wire.TxOut, - txVersion int32) (*wire.MsgTx, error) { - - tx := wire.NewMsgTx(txVersion) - tx.AddTxIn(&wire.TxIn{ - PreviousOutPoint: *csvUTXO, - Sequence: sequence, - }) - tx.AddTxOut(targetOutput) - - b := txscript.NewScriptBuilder(). - AddOp(txscript.OP_TRUE). - AddData(redeemScript) - - sigScript, err := b.Script() - if err != nil { - return nil, err - } - tx.TxIn[0].SignatureScript = sigScript - - return tx, nil -} - -// assertTxInBlock asserts a transaction with the specified txid is found -// within the block with the passed block hash. -func assertTxInBlock(r *rpctest.Harness, t *testing.T, blockHash *chainhash.Hash, - txid *chainhash.Hash) { - - block, err := r.Client.GetBlock(blockHash) - if err != nil { - t.Fatalf("unable to get block: %v", err) - } - if len(block.Transactions) < 2 { - t.Fatal("target transaction was not mined") - } - - for _, txn := range block.Transactions { - txHash := txn.TxHash() - if txn.TxHash() == txHash { - return - } - } - - _, _, line, _ := runtime.Caller(1) - t.Fatalf("assertion failed at line %v: txid %v was not found in "+ - "block %v", line, txid, blockHash) -} - -// TestBIP0068AndBIP0112Activation tests for the proper adherence to the BIP -// 112 and BIP 68 rule-set after the activation of the CSV-package soft-fork. -// -// Overview: -// - Pre soft-fork: -// 1. A transaction spending a CSV output validly should be rejected from the -// mempool, but accepted in a valid generated block including the -// transaction. -// -// - Post soft-fork: -// 1. See the cases exercised within the table driven tests towards the end -// of this test. -func TestBIP0068AndBIP0112Activation(t *testing.T) { - t.Parallel() - - // We'd like the test proper evaluation and validation of the BIP 68 - // (sequence locks) and BIP 112 rule-sets which add input-age based - // relative lock times. - - btcdCfg := []string{"--rejectnonstd"} - r, err := rpctest.New(&chaincfg.SimNetParams, nil, btcdCfg, "") - if err != nil { - t.Fatal("unable to create primary harness: ", err) - } - if err := r.SetUp(true, 1); err != nil { - t.Fatalf("unable to setup test chain: %v", err) - } - defer r.TearDown() - - assertSoftForkStatus(r, t, csvKey, blockchain.ThresholdStarted) - - harnessAddr, err := r.NewAddress() - if err != nil { - t.Fatalf("unable to obtain harness address: %v", err) - } - harnessScript, err := txscript.PayToAddrScript(harnessAddr) - if err != nil { - t.Fatalf("unable to generate pkScript: %v", err) - } - - const ( - outputAmt = btcutil.SatoshiPerBitcoin - relativeBlockLock = 10 - ) - - sweepOutput := &wire.TxOut{ - Value: outputAmt - 5000, - PkScript: harnessScript, - } - - // As the soft-fork hasn't yet activated _any_ transaction version - // which uses the CSV opcode should be accepted. Since at this point, - // CSV doesn't actually exist, it's just a NOP. - for txVersion := int32(0); txVersion < 3; txVersion++ { - // Create a trivially spendable output with a CSV lock-time of - // 10 relative blocks. - redeemScript, testUTXO, tx, err := createCSVOutput(r, t, outputAmt, - relativeBlockLock, false) - if err != nil { - t.Fatalf("unable to create CSV encumbered output: %v", err) - } - - // As the transaction is p2sh it should be accepted into the - // mempool and found within the next generated block. - if _, err := r.Client.SendRawTransaction(tx, true); err != nil { - t.Fatalf("unable to broadcast tx: %v", err) - } - blocks, err := r.Client.Generate(1) - if err != nil { - t.Fatalf("unable to generate blocks: %v", err) - } - txid := tx.TxHash() - assertTxInBlock(r, t, blocks[0], &txid) - - // Generate a custom transaction which spends the CSV output. - sequenceNum := blockchain.LockTimeToSequence(false, 10) - spendingTx, err := spendCSVOutput(redeemScript, testUTXO, - sequenceNum, sweepOutput, txVersion) - if err != nil { - t.Fatalf("unable to spend csv output: %v", err) - } - - // This transaction should be rejected from the mempool since - // CSV validation is already mempool policy pre-fork. - _, err = r.Client.SendRawTransaction(spendingTx, true) - if err == nil { - t.Fatalf("transaction should have been rejected, but was " + - "instead accepted") - } - - // However, this transaction should be accepted in a custom - // generated block as CSV validation for scripts within blocks - // shouldn't yet be active. - txns := []*btcutil.Tx{btcutil.NewTx(spendingTx)} - block, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{}) - if err != nil { - t.Fatalf("unable to submit block: %v", err) - } - txid = spendingTx.TxHash() - assertTxInBlock(r, t, block.Hash(), &txid) - } - - // At this point, the block height should be 107: we started at height - // 101, then generated 2 blocks in each loop iteration above. - assertChainHeight(r, t, 107) - - // With the height at 107 we need 200 blocks to be mined after the - // genesis target period, so we mine 192 blocks. This'll put us at - // height 299. The getblockchaininfo call checks the state for the - // block AFTER the current height. - numBlocks := (r.ActiveNet.MinerConfirmationWindow * 2) - 8 - if _, err := r.Client.Generate(numBlocks); err != nil { - t.Fatalf("unable to generate blocks: %v", err) - } - - assertChainHeight(r, t, 299) - assertSoftForkStatus(r, t, csvKey, blockchain.ThresholdActive) - - // Knowing the number of outputs needed for the tests below, create a - // fresh output for use within each of the test-cases below. - const relativeTimeLock = 512 - const numTests = 8 - type csvOutput struct { - RedeemScript []byte - Utxo *wire.OutPoint - Timelock int32 - } - var spendableInputs [numTests]csvOutput - - // Create three outputs which have a block-based sequence locks, and - // three outputs which use the above time based sequence lock. - for i := 0; i < numTests; i++ { - timeLock := relativeTimeLock - isSeconds := true - if i < 7 { - timeLock = relativeBlockLock - isSeconds = false - } - - redeemScript, utxo, tx, err := createCSVOutput(r, t, outputAmt, - int32(timeLock), isSeconds) - if err != nil { - t.Fatalf("unable to create CSV output: %v", err) - } - - if _, err := r.Client.SendRawTransaction(tx, true); err != nil { - t.Fatalf("unable to broadcast transaction: %v", err) - } - - spendableInputs[i] = csvOutput{ - RedeemScript: redeemScript, - Utxo: utxo, - Timelock: int32(timeLock), - } - } - - // Mine a single block including all the transactions generated above. - if _, err := r.Client.Generate(1); err != nil { - t.Fatalf("unable to generate block: %v", err) - } - - // Now mine 10 additional blocks giving the inputs generated above a - // age of 11. Space out each block 10 minutes after the previous block. - prevBlockHash, err := r.Client.GetBestBlockHash() - if err != nil { - t.Fatalf("unable to get prior block hash: %v", err) - } - prevBlock, err := r.Client.GetBlock(prevBlockHash) - if err != nil { - t.Fatalf("unable to get block: %v", err) - } - for i := 0; i < relativeBlockLock; i++ { - timeStamp := prevBlock.Header.Timestamp.Add(time.Minute * 10) - b, err := r.GenerateAndSubmitBlock(nil, -1, timeStamp) - if err != nil { - t.Fatalf("unable to generate block: %v", err) - } - - prevBlock = b.MsgBlock() - } - - // A helper function to create fully signed transactions in-line during - // the array initialization below. - var inputIndex uint32 - makeTxCase := func(sequenceNum uint32, txVersion int32) *wire.MsgTx { - csvInput := spendableInputs[inputIndex] - - tx, err := spendCSVOutput(csvInput.RedeemScript, csvInput.Utxo, - sequenceNum, sweepOutput, txVersion) - if err != nil { - t.Fatalf("unable to spend CSV output: %v", err) - } - - inputIndex++ - return tx - } - - tests := [numTests]struct { - tx *wire.MsgTx - accept bool - }{ - // A valid transaction with a single input a sequence number - // creating a 100 block relative time-lock. This transaction - // should be rejected as its version number is 1, and only tx - // of version > 2 will trigger the CSV behavior. - { - tx: makeTxCase(blockchain.LockTimeToSequence(false, 100), 1), - accept: false, - }, - // A transaction of version 2 spending a single input. The - // input has a relative time-lock of 1 block, but the disable - // bit it set. The transaction should be rejected as a result. - { - tx: makeTxCase( - blockchain.LockTimeToSequence(false, 1)|wire.SequenceLockTimeDisabled, - 2, - ), - accept: false, - }, - // A v2 transaction with a single input having a 9 block - // relative time lock. The referenced input is 11 blocks old, - // but the CSV output requires a 10 block relative lock-time. - // Therefore, the transaction should be rejected. - { - tx: makeTxCase(blockchain.LockTimeToSequence(false, 9), 2), - accept: false, - }, - // A v2 transaction with a single input having a 10 block - // relative time lock. The referenced input is 11 blocks old so - // the transaction should be accepted. - { - tx: makeTxCase(blockchain.LockTimeToSequence(false, 10), 2), - accept: true, - }, - // A v2 transaction with a single input having a 11 block - // relative time lock. The input referenced has an input age of - // 11 and the CSV op-code requires 10 blocks to have passed, so - // this transaction should be accepted. - { - tx: makeTxCase(blockchain.LockTimeToSequence(false, 11), 2), - accept: true, - }, - // A v2 transaction whose input has a 1000 blck relative time - // lock. This should be rejected as the input's age is only 11 - // blocks. - { - tx: makeTxCase(blockchain.LockTimeToSequence(false, 1000), 2), - accept: false, - }, - // A v2 transaction with a single input having a 512,000 second - // relative time-lock. This transaction should be rejected as 6 - // days worth of blocks haven't yet been mined. The referenced - // input doesn't have sufficient age. - { - tx: makeTxCase(blockchain.LockTimeToSequence(true, 512000), 2), - accept: false, - }, - // A v2 transaction whose single input has a 512 second - // relative time-lock. This transaction should be accepted as - // finalized. - { - tx: makeTxCase(blockchain.LockTimeToSequence(true, 512), 2), - accept: true, - }, - } - - for i, test := range tests { - txid, err := r.Client.SendRawTransaction(test.tx, true) - switch { - // Test case passes, nothing further to report. - case test.accept && err == nil: - - // Transaction should have been accepted but we have a non-nil - // error. - case test.accept && err != nil: - t.Fatalf("test #%d, transaction should be accepted, "+ - "but was rejected: %v", i, err) - - // Transaction should have been rejected, but it was accepted. - case !test.accept && err == nil: - t.Fatalf("test #%d, transaction should be rejected, "+ - "but was accepted", i) - - // Transaction was rejected as wanted, nothing more to do. - case !test.accept && err != nil: - } - - // If the transaction should be rejected, manually mine a block - // with the non-final transaction. It should be rejected. - if !test.accept { - txns := []*btcutil.Tx{btcutil.NewTx(test.tx)} - _, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{}) - if err == nil { - t.Fatalf("test #%d, invalid block accepted", i) - } - - continue - } - - // Generate a block, the transaction should be included within - // the newly mined block. - blockHashes, err := r.Client.Generate(1) - if err != nil { - t.Fatalf("unable to mine block: %v", err) - } - assertTxInBlock(r, t, blockHashes[0], txid) - } -} diff --git a/btcd.go b/ppcd.go similarity index 100% rename from btcd.go rename to ppcd.go diff --git a/release/release.sh b/release/release.sh index de49f641221..d869140823a 100755 --- a/release/release.sh +++ b/release/release.sh @@ -5,7 +5,7 @@ # Use of this source code is governed by an ISC # license that can be found in the LICENSE file. -# Simple bash script to build basic btcd tools for all the platforms we support +# Simple bash script to build basic ppcd tools for all the platforms we support # with the golang cross-compiler. set -e @@ -22,7 +22,7 @@ fi go mod vendor tar -cvzf vendor.tar.gz vendor -PACKAGE=btcd +PACKAGE=ppcd MAINDIR=$PACKAGE-$TAG mkdir -p $MAINDIR @@ -72,7 +72,7 @@ SYS=${BTCDBUILDSYS:-" # Use the first element of $GOPATH in the case where GOPATH is a list # (something that is totally allowed). -PKG="github.com/btcsuite/btcd" +PKG="github.com/peercoin/ppcd" COMMIT=$(git describe --abbrev=40 --dirty) for i in $SYS; do @@ -92,8 +92,8 @@ for i in $SYS; do cd $PACKAGE-$i-$TAG echo "Building:" $OS $ARCH $ARM - env CGO_ENABLED=0 GOOS=$OS GOARCH=$ARCH GOARM=$ARM go build -v -trimpath -ldflags="-s -w -buildid=" github.com/btcsuite/btcd - env CGO_ENABLED=0 GOOS=$OS GOARCH=$ARCH GOARM=$ARM go build -v -trimpath -ldflags="-s -w -buildid=" github.com/btcsuite/btcd/cmd/btcctl + env CGO_ENABLED=0 GOOS=$OS GOARCH=$ARCH GOARM=$ARM go build -v -trimpath -ldflags="-s -w -buildid=" github.com/peercoin/ppcd + env CGO_ENABLED=0 GOOS=$OS GOARCH=$ARCH GOARM=$ARM go build -v -trimpath -ldflags="-s -w -buildid=" github.com/peercoin/ppcd/cmd/btcctl cd .. if [[ $OS = "windows" ]]; then