From 82b9729474247c772f8e4f854dbf64b73097e4b1 Mon Sep 17 00:00:00 2001 From: mattfoley8 Date: Fri, 7 Apr 2023 13:32:07 -0400 Subject: [PATCH 01/84] Test backend CI against core with relic dependency. --- test.Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test.Dockerfile b/test.Dockerfile index d078d61c..94369939 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -2,7 +2,7 @@ FROM alpine:latest AS backend RUN apk update RUN apk upgrade -RUN apk add --update go gcc g++ vips-dev git +RUN apk add --update bash cmake git go gcc g++ make vips-dev WORKDIR /deso/src @@ -17,6 +17,7 @@ COPY go.mod . COPY go.sum . RUN go mod download +RUN /deso/src/core/scripts/install-relic.sh # include backend src COPY apis apis @@ -30,4 +31,4 @@ COPY main.go . # build backend RUN GOOS=linux go build -mod=mod -a -installsuffix cgo -o bin/backend main.go -ENTRYPOINT ["go", "test", "-v", "github.com/deso-protocol/backend/routes"] +ENTRYPOINT ["go", "test", "-tags", "relic", "-v", "github.com/deso-protocol/backend/routes"] From 6834066c530c1b001f8ed9506d9165303f1a99d2 Mon Sep 17 00:00:00 2001 From: mattfoley8 Date: Fri, 7 Apr 2023 13:34:03 -0400 Subject: [PATCH 02/84] Checkout specific branch just for testing purposes. --- test.Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.Dockerfile b/test.Dockerfile index 94369939..78e65790 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -2,14 +2,14 @@ FROM alpine:latest AS backend RUN apk update RUN apk upgrade -RUN apk add --update bash cmake git go gcc g++ make vips-dev +RUN apk add --update bash cmake go gcc g++ make vips-dev git WORKDIR /deso/src RUN git clone https://github.com/deso-protocol/core.git WORKDIR /deso/src/core -RUN git pull +RUN git checkout mf/add-bls-signature-utils && git pull origin mf/add-bls-signature-utils WORKDIR /deso/src/backend From 6a6576656806a393de7b08310693e88824ef807a Mon Sep 17 00:00:00 2001 From: mattfoley8 Date: Thu, 1 Jun 2023 09:55:33 -0400 Subject: [PATCH 03/84] Update test Dockerfile. --- test.Dockerfile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test.Dockerfile b/test.Dockerfile index 78e65790..ce28ac59 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -2,14 +2,21 @@ FROM alpine:latest AS backend RUN apk update RUN apk upgrade -RUN apk add --update bash cmake go gcc g++ make vips-dev git +RUN apk add --update bash cmake gcc g++ make vips-dev git + +COPY --from=golang:1.20-alpine /usr/local/go/ /usr/local/go/ +ENV PATH="/usr/local/go/bin:${PATH}" WORKDIR /deso/src RUN git clone https://github.com/deso-protocol/core.git WORKDIR /deso/src/core -RUN git checkout mf/add-bls-signature-utils && git pull origin mf/add-bls-signature-utils +RUN git checkout mf/add-bls-signature-utils && \ + git pull origin mf/add-bls-signature-utils # TODO: Revert to `git pull` once core PR is merged. + +RUN go mod download +RUN ./scripts/install-relic.sh WORKDIR /deso/src/backend @@ -17,7 +24,6 @@ COPY go.mod . COPY go.sum . RUN go mod download -RUN /deso/src/core/scripts/install-relic.sh # include backend src COPY apis apis From 5428fa79b69fbdc225bc09a016e86223e12e4687 Mon Sep 17 00:00:00 2001 From: mattfoley8 Date: Fri, 2 Jun 2023 12:40:05 -0400 Subject: [PATCH 04/84] Fix failing build stages. --- Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index d06304f6..d7fec234 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,10 +25,11 @@ COPY backend/countries countries COPY backend/main.go . # include core src +COPY core/bls ../core/bls COPY core/desohash ../core/desohash -COPY core/cmd ../core/cmd -COPY core/lib ../core/lib -COPY core/migrate ../core/migrate +COPY core/cmd ../core/cmd +COPY core/lib ../core/lib +COPY core/migrate ../core/migrate # build backend RUN GOOS=linux go build -mod=mod -a -installsuffix cgo -o bin/backend main.go From cc557618b65717f473a7f481f0fb7c1f8eb1f4a6 Mon Sep 17 00:00:00 2001 From: mattfoley8 Date: Mon, 12 Jun 2023 10:55:44 -0400 Subject: [PATCH 05/84] Add new deps. --- go.mod | 2 ++ go.sum | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/go.mod b/go.mod index cdcecd6d..b4b79c8d 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( cloud.google.com/go v0.81.0 // indirect github.com/DataDog/datadog-go v4.5.0+incompatible // indirect github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect github.com/bwesterb/go-ristretto v1.2.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect @@ -82,6 +83,7 @@ require ( github.com/mattn/goveralls v0.0.6 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/oleiade/lane v1.0.1 // indirect + github.com/onflow/flow-go/crypto v0.24.7 // indirect github.com/pelletier/go-toml v1.7.0 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/philhofer/fwd v1.1.1 // indirect diff --git a/go.sum b/go.sum index 00904dfa..3dbb5e5e 100644 --- a/go.sum +++ b/go.sum @@ -86,6 +86,8 @@ github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnC github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= +github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= @@ -372,6 +374,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -433,6 +436,8 @@ github.com/oleiade/lane v1.0.1 h1:hXofkn7GEOubzTwNpeL9MaNy8WxolCYb9cInAIeqShU= github.com/oleiade/lane v1.0.1/go.mod h1:IyTkraa4maLfjq/GmHR+Dxb4kCMtEGeb+qmhlrQ5Mk4= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onflow/flow-go/crypto v0.24.7 h1:RCLuB83At4z5wkAyUCF7MYEnPoIIOHghJaODuJyEoW0= +github.com/onflow/flow-go/crypto v0.24.7/go.mod h1:fqCzkIBBMRRkciVrvW21rECKq1oD7Q6u+bCI78lfNX0= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -498,6 +503,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -541,6 +547,7 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/supranational/blst v0.3.10 h1:CMciDZ/h4pXDDXQASe8ZGTNKUiVNxVVA5hpci2Uuhuk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= @@ -1018,6 +1025,7 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w= mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ= +pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 06c8c36049bff657f43eb953d95d2c0c66e1a1d6 Mon Sep 17 00:00:00 2001 From: Matt Foley <100429827+mattfoley8@users.noreply.github.com> Date: Tue, 13 Jun 2023 10:41:33 -0400 Subject: [PATCH 06/84] Allow ParamUpdater to update PoS consensus params (#499) * Allow ParamUpdater to update PoS GlobalParams. * Add epoch number to get pos params call. * Change core branch in test Dockerfile. * Add test for updating global params. * Fix bugs in testing updating global params. * Checkout correct core branch. * Change core branch. --- routes/admin_transaction.go | 84 +++++++++++++++++-- routes/admin_transaction_test.go | 137 +++++++++++++++++++++++++++++++ test.Dockerfile | 5 +- 3 files changed, 219 insertions(+), 7 deletions(-) create mode 100644 routes/admin_transaction_test.go diff --git a/routes/admin_transaction.go b/routes/admin_transaction.go index eea78f06..3643e759 100644 --- a/routes/admin_transaction.go +++ b/routes/admin_transaction.go @@ -31,6 +31,26 @@ type GetGlobalParamsResponse struct { // The maximum number of copies a single NFT can have. MaxCopiesPerNFT uint64 `safeForLogging:"true"` + + // StakeLockupEpochDuration is the number of epochs that a + // user must wait before unlocking their unstaked stake. + StakeLockupEpochDuration uint64 `safeForLogging:"true"` + + // ValidatorJailEpochDuration is the number of epochs that a validator must + // wait after being jailed before submitting an UnjailValidator txn. + ValidatorJailEpochDuration uint64 `safeForLogging:"true"` + + // LeaderScheduleMaxNumValidators is the maximum number of validators that + // are included when generating a new Proof-of-Stake leader schedule. + LeaderScheduleMaxNumValidators uint64 `safeForLogging:"true"` + + // EpochDurationNumBlocks is the number of blocks included in one epoch. + EpochDurationNumBlocks uint64 `safeForLogging:"true"` + + // JailInactiveValidatorGracePeriodEpochs is the number of epochs we + // allow a validator to be inactive for (neither voting nor proposing + // blocks) before they are jailed. + JailInactiveValidatorGracePeriodEpochs uint64 `safeForLogging:"true"` } func (fes *APIServer) GetGlobalParams(ww http.ResponseWriter, req *http.Request) { @@ -50,11 +70,16 @@ func (fes *APIServer) GetGlobalParams(ww http.ResponseWriter, req *http.Request) globalParamsEntry := utxoView.GlobalParamsEntry // Return all the data associated with the transaction in the response res := GetGlobalParamsResponse{ - USDCentsPerBitcoin: globalParamsEntry.USDCentsPerBitcoin, - CreateProfileFeeNanos: globalParamsEntry.CreateProfileFeeNanos, - MinimumNetworkFeeNanosPerKB: globalParamsEntry.MinimumNetworkFeeNanosPerKB, - CreateNFTFeeNanos: globalParamsEntry.CreateNFTFeeNanos, - MaxCopiesPerNFT: globalParamsEntry.MaxCopiesPerNFT, + USDCentsPerBitcoin: globalParamsEntry.USDCentsPerBitcoin, + CreateProfileFeeNanos: globalParamsEntry.CreateProfileFeeNanos, + MinimumNetworkFeeNanosPerKB: globalParamsEntry.MinimumNetworkFeeNanosPerKB, + CreateNFTFeeNanos: globalParamsEntry.CreateNFTFeeNanos, + MaxCopiesPerNFT: globalParamsEntry.MaxCopiesPerNFT, + StakeLockupEpochDuration: utxoView.GetCurrentGlobalParam(lib.StakeLockupEpochDuration), + ValidatorJailEpochDuration: utxoView.GetCurrentGlobalParam(lib.ValidatorJailEpochDuration), + LeaderScheduleMaxNumValidators: utxoView.GetCurrentGlobalParam(lib.LeaderScheduleMaxNumValidators), + EpochDurationNumBlocks: utxoView.GetCurrentGlobalParam(lib.EpochDurationNumBlocks), + JailInactiveValidatorGracePeriodEpochs: utxoView.GetCurrentGlobalParam(lib.JailInactiveValidatorGracePeriodEpochs), } if err := json.NewEncoder(ww).Encode(res); err != nil { _AddBadRequestError(ww, fmt.Sprintf("GetGlobalParams: Problem encoding response as JSON: %v", err)) @@ -84,6 +109,26 @@ type UpdateGlobalParamsRequest struct { // heights on nonces. MaxNonceExpirationBlockHeightOffset int64 `safeForLogging:"true"` + // StakeLockupEpochDuration is the number of epochs that a + // user must wait before unlocking their unstaked stake. + StakeLockupEpochDuration uint64 `safeForLogging:"true"` + + // ValidatorJailEpochDuration is the number of epochs that a validator must + // wait after being jailed before submitting an UnjailValidator txn. + ValidatorJailEpochDuration uint64 `safeForLogging:"true"` + + // LeaderScheduleMaxNumValidators is the maximum number of validators that + // are included when generating a new Proof-of-Stake leader schedule. + LeaderScheduleMaxNumValidators uint64 `safeForLogging:"true"` + + // EpochDurationNumBlocks is the number of blocks included in one epoch. + EpochDurationNumBlocks uint64 `safeForLogging:"true"` + + // JailInactiveValidatorGracePeriodEpochs is the number of epochs we + // allow a validator to be inactive for (neither voting nor proposing + // blocks) before they are jailed. + JailInactiveValidatorGracePeriodEpochs uint64 `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` // No need to specify ProfileEntryResponse in each TransactionFee @@ -172,6 +217,34 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque maxNonceExpirationBlockHeightOffset = requestData.MaxNonceExpirationBlockHeightOffset } + extraData := make(map[string][]byte) + + // Update Proof of Stake consensus related global params if they have changed. + if requestData.StakeLockupEpochDuration > 0 && + requestData.StakeLockupEpochDuration != utxoView.GetCurrentGlobalParam(lib.StakeLockupEpochDuration) { + extraData[lib.StakeLockupEpochDuration.ToString()] = lib.UintToBuf(requestData.StakeLockupEpochDuration) + } + + if requestData.ValidatorJailEpochDuration > 0 && + requestData.ValidatorJailEpochDuration != utxoView.GetCurrentGlobalParam(lib.ValidatorJailEpochDuration) { + extraData[lib.ValidatorJailEpochDuration.ToString()] = lib.UintToBuf(requestData.ValidatorJailEpochDuration) + } + + if requestData.LeaderScheduleMaxNumValidators > 0 && + requestData.LeaderScheduleMaxNumValidators != utxoView.GetCurrentGlobalParam(lib.LeaderScheduleMaxNumValidators) { + extraData[lib.LeaderScheduleMaxNumValidators.ToString()] = lib.UintToBuf(requestData.LeaderScheduleMaxNumValidators) + } + + if requestData.EpochDurationNumBlocks > 0 && + requestData.EpochDurationNumBlocks != utxoView.GetCurrentGlobalParam(lib.EpochDurationNumBlocks) { + extraData[lib.EpochDurationNumBlocks.ToString()] = lib.UintToBuf(requestData.EpochDurationNumBlocks) + } + + if requestData.JailInactiveValidatorGracePeriodEpochs > 0 && + requestData.JailInactiveValidatorGracePeriodEpochs != utxoView.GetCurrentGlobalParam(lib.JailInactiveValidatorGracePeriodEpochs) { + extraData[lib.JailInactiveValidatorGracePeriodEpochs.ToString()] = lib.UintToBuf(requestData.JailInactiveValidatorGracePeriodEpochs) + } + // Try and create the update txn for the user. txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateUpdateGlobalParamsTxn( updaterPkBytes, @@ -182,6 +255,7 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque minimumNetworkFeeNanosPerKb, []byte{}, maxNonceExpirationBlockHeightOffset, + extraData, requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { diff --git a/routes/admin_transaction_test.go b/routes/admin_transaction_test.go new file mode 100644 index 00000000..06d67f7f --- /dev/null +++ b/routes/admin_transaction_test.go @@ -0,0 +1,137 @@ +package routes + +import ( + "bytes" + "encoding/json" + "github.com/deso-protocol/core/lib" + "github.com/stretchr/testify/require" + "io" + "net/http" + "net/http/httptest" + "testing" +) + +func TestUpdateGlobalParams(t *testing.T) { + // Hard-coded test constants + adminPublicKeyBase58Check := "tBCKWVydPvhXyxSVhntXCw7wUev2fUx64h84FLAfz4JStsdBAq4v9r" + adminJWT := "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NDQ3MDU1Mzh9.LXA2uT8tm-6DXDwTXaCRyqqbFNa96jLl_02LXyAwq58PbVPe28hrICP3P-D5g9mktPJolSVXK_UebRcL5oYCWg" + + // Init api server + apiServer := newTestApiServer(t) + apiServer.Config.SuperAdminPublicKeys = []string{adminPublicKeyBase58Check} + senderPkBytes, _, err := lib.Base58CheckDecode(senderPkString) + require.NoError(t, err) + apiServer.Params.ExtraRegtestParamUpdaterKeys[lib.MakePkMapKey(senderPkBytes)] = true + + // Helper utils + getGlobalParams := func() *GetGlobalParamsResponse { + // Send POST request. + body := GetGlobalParamsRequest{} + bodyJSON, err := json.Marshal(body) + require.NoError(t, err) + request, _ := http.NewRequest("POST", RoutePathGetGlobalParams, bytes.NewBuffer(bodyJSON)) + request.Header.Set("Content-Type", "application/json") + response := httptest.NewRecorder() + apiServer.router.ServeHTTP(response, request) + require.NotContains(t, string(response.Body.Bytes()), "error") + + // Decode response. + decoder := json.NewDecoder(io.LimitReader(response.Body, MaxRequestBodySizeBytes)) + globalParams := GetGlobalParamsResponse{} + err = decoder.Decode(&globalParams) + return &globalParams + } + + updateGlobalParams := func(body *UpdateGlobalParamsRequest) { + // Add JWT auth to body of request. + type MergedBody struct { + AdminRequest + UpdateGlobalParamsRequest + } + mergedBody := MergedBody{ + AdminRequest: AdminRequest{ + JWT: adminJWT, AdminPublicKey: adminPublicKeyBase58Check, + }, + UpdateGlobalParamsRequest: *body, + } + + // Send POST request. + bodyJSON, err := json.Marshal(mergedBody) + require.NoError(t, err) + request, _ := http.NewRequest("POST", RoutePathUpdateGlobalParams, bytes.NewBuffer(bodyJSON)) + request.Header.Set("Content-Type", "application/json") + response := httptest.NewRecorder() + apiServer.router.ServeHTTP(response, request) + require.NotContains(t, string(response.Body.Bytes()), "error") + + // Decode response. + decoder := json.NewDecoder(io.LimitReader(response.Body, MaxRequestBodySizeBytes)) + updateGlobalParamsResponse := UpdateGlobalParamsResponse{} + err = decoder.Decode(&updateGlobalParamsResponse) + require.NoError(t, err) + txn := updateGlobalParamsResponse.Transaction + + // Sign txn. + require.Nil(t, txn.Signature.Sign) + signTxn(t, txn, senderPrivString) + require.NotNil(t, txn.Signature.Sign) + + // Submit txn. + _, err = submitTxn(t, apiServer, txn) + require.NoError(t, err) + } + + // Tests + { + // Confirm default GlobalParams. + globalParams := getGlobalParams() + require.Zero(t, globalParams.MinimumNetworkFeeNanosPerKB) + require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(3)) + require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(3)) + require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(100)) + require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(3600)) + require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(48)) + } + { + // Update all GlobalParam fields. + updateGlobalParams(&UpdateGlobalParamsRequest{ + UpdaterPublicKeyBase58Check: senderPkString, + MinimumNetworkFeeNanosPerKB: 99, + StakeLockupEpochDuration: 4, + ValidatorJailEpochDuration: 4, + LeaderScheduleMaxNumValidators: 101, + EpochDurationNumBlocks: 3601, + JailInactiveValidatorGracePeriodEpochs: 49, + MinFeeRateNanosPerKB: 99, + }) + } + { + // Verify all updated GlobalParam fields. + globalParams := getGlobalParams() + require.Equal(t, globalParams.MinimumNetworkFeeNanosPerKB, uint64(99)) + require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(4)) + require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(4)) + require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(101)) + require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(3601)) + require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(49)) + } + { + // Update only one GlobalParam field. + updateGlobalParams(&UpdateGlobalParamsRequest{ + UpdaterPublicKeyBase58Check: senderPkString, + MinimumNetworkFeeNanosPerKB: 99, + JailInactiveValidatorGracePeriodEpochs: 50, + MinFeeRateNanosPerKB: 99, + }) + } + { + // Verify updated GlobalParam field. And other fields retain old values. + globalParams := getGlobalParams() + require.Equal(t, globalParams.MinimumNetworkFeeNanosPerKB, uint64(99)) + require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(4)) + require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(4)) + require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(101)) + require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(3601)) + require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(50)) + } +} diff --git a/test.Dockerfile b/test.Dockerfile index ce28ac59..19d7e5ad 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -12,8 +12,9 @@ WORKDIR /deso/src RUN git clone https://github.com/deso-protocol/core.git WORKDIR /deso/src/core -RUN git checkout mf/add-bls-signature-utils && \ - git pull origin mf/add-bls-signature-utils # TODO: Revert to `git pull` once core PR is merged. +RUN git pull && \ + git checkout mf/pos-merge-20230605 && \ + git pull origin mf/pos-merge-20230605 # TODO: Revert to `git pull` once core PR is merged. RUN go mod download RUN ./scripts/install-relic.sh From 898b8aabddd34171607c2707b82961bd566275cd Mon Sep 17 00:00:00 2001 From: Matt Foley <100429827+mattfoley8@users.noreply.github.com> Date: Tue, 13 Jun 2023 11:55:41 -0400 Subject: [PATCH 07/84] Mf/add validator registration endpoints (#500) * Add validator registration endpoints. * Allow ExtraData to be logged. --- routes/server.go | 17 +++ routes/validators.go | 212 ++++++++++++++++++++++++++++++++++++++ routes/validators_test.go | 124 ++++++++++++++++++++++ 3 files changed, 353 insertions(+) create mode 100644 routes/validators.go create mode 100644 routes/validators_test.go diff --git a/routes/server.go b/routes/server.go index cc6208ec..9dca3ef8 100644 --- a/routes/server.go +++ b/routes/server.go @@ -311,6 +311,9 @@ const ( // snapshot.go RoutePathSnapshotEpochMetadata = "/api/v0/snapshot-epoch-metadata" RoutePathStateChecksum = "/api/v0/state-checksum" + + // validators.go + RoutePathValidators = "/api/v0/validators" ) // APIServer provides the interface between the blockchain and things like the @@ -1270,6 +1273,20 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.CountPostAssociationsByValue, PublicAccess, }, + { + "RegisterAsValidator", + []string{"POST", "OPTIONS"}, + RoutePathValidators + "/register", + fes.RegisterAsValidator, + PublicAccess, + }, + { + "UnregisterAsValidator", + []string{"POST", "OPTIONS"}, + RoutePathValidators + "/unregister", + fes.UnregisterAsValidator, + PublicAccess, + }, // Jumio Routes { "JumioBegin", diff --git a/routes/validators.go b/routes/validators.go new file mode 100644 index 00000000..e013ab35 --- /dev/null +++ b/routes/validators.go @@ -0,0 +1,212 @@ +package routes + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "github.com/deso-protocol/core/bls" + "github.com/deso-protocol/core/lib" + "io" + "net/http" +) + +type RegisterAsValidatorRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + Domains []string `safeForLogging:"true"` + DisableDelegatedStake bool `safeForLogging:"true"` + VotingPublicKey string `safeForLogging:"true"` + VotingPublicKeySignature string `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type UnregisterAsValidatorRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type ValidatorTxnResponse struct { + SpendAmountNanos uint64 + TotalInputNanos uint64 + ChangeAmountNanos uint64 + FeeNanos uint64 + Transaction *lib.MsgDeSoTxn + TransactionHex string + TxnHashHex string +} + +func (fes *APIServer) RegisterAsValidator(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := RegisterAsValidatorRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, "RegisterAsValidator: problem parsing request body") + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes. + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, "RegisterAsValidator: must provide a TransactorPublicKeyBase58Check") + return + } + transactorPublicKeyBytes, err := GetPubKeyBytesFromBase58Check(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddInternalServerError(ww, "RegisterAsValidator: problem getting public key for the transactor") + return + } + + // Convert Domains from []string to [][]byte. + var domains [][]byte + for _, domain := range requestData.Domains { + domains = append(domains, []byte(domain)) + } + + // Convert VotingPublicKeyString to VotingPublicKey. + votingPublicKey, err := (&bls.PublicKey{}).FromString(requestData.VotingPublicKey) + if err != nil { + _AddBadRequestError(ww, "RegisterAsValidator: problem parsing VotingPublicKey") + return + } + + // Convert VotingPublicKeySignatureString to VotingPublicKeySignature. + votingPublicKeySignature, err := (&bls.Signature{}).FromString(requestData.VotingPublicKeySignature) + if err != nil { + _AddBadRequestError(ww, "RegisterAsValidator: problem parsing VotingPublicKeySignature") + return + } + + // Parse ExtraData. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, "RegisterAsValidator: invalid ExtraData provided") + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeRegisterAsValidator, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, "RegisterAsValidator: specified TransactionFees are invalid") + return + } + + // Create transaction. + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateRegisterAsValidatorTxn( + transactorPublicKeyBytes, + &lib.RegisterAsValidatorMetadata{ + Domains: domains, + DisableDelegatedStake: requestData.DisableDelegatedStake, + VotingPublicKey: votingPublicKey, + VotingPublicKeySignature: votingPublicKeySignature, + }, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("RegisterAsValidator: problem creating txn: %v", err)) + return + } + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, "RegisterAsValidator: problem encoding txn to bytes") + return + } + res := ValidatorTxnResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, "RegisterAsValidator: problem encoding response as JSON") + return + } +} + +func (fes *APIServer) UnregisterAsValidator(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := UnregisterAsValidatorRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, "UnregisterAsValidator: problem parsing request body") + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes. + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, "UnregisterAsValidator: must provide a TransactorPublicKeyBase58Check") + return + } + transactorPublicKeyBytes, err := GetPubKeyBytesFromBase58Check(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddInternalServerError(ww, "UnregisterAsValidator: problem getting public key for the transactor") + return + } + + // Parse ExtraData. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, "UnregisterAsValidator: invalid ExtraData provided") + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeRegisterAsValidator, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, "UnregisterAsValidator: specified TransactionFees are invalid") + return + } + + // Create transaction. + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateUnregisterAsValidatorTxn( + transactorPublicKeyBytes, + &lib.UnregisterAsValidatorMetadata{}, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("UnregisterAsValidator: problem creating txn: %v", err)) + return + } + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, "UnregisterAsValidator: problem encoding txn to bytes") + return + } + res := ValidatorTxnResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, "UnregisterAsValidator: problem encoding response as JSON") + return + } +} diff --git a/routes/validators_test.go b/routes/validators_test.go new file mode 100644 index 00000000..9a56850e --- /dev/null +++ b/routes/validators_test.go @@ -0,0 +1,124 @@ +//go:build relic + +package routes + +import ( + "bytes" + "encoding/json" + "github.com/deso-protocol/core/bls" + "github.com/deso-protocol/core/lib" + "github.com/stretchr/testify/require" + "io" + "net/http" + "net/http/httptest" + "testing" +) + +func TestValidatorRegistration(t *testing.T) { + apiServer := newTestApiServer(t) + + // Convert senderPkString to senderPkBytes. + senderPkBytes, _, err := lib.Base58CheckDecode(senderPkString) + require.NoError(t, err) + + { + // sender registers as a validator. + + // Send POST request. + votingPublicKey, votingSignature := _generateVotingPublicKeyAndSignature(t, senderPkBytes) + extraData := map[string]string{"Foo": "Bar"} + body := &RegisterAsValidatorRequest{ + TransactorPublicKeyBase58Check: senderPkString, + Domains: []string{"https://sender-001.deso.com", "https://sender-002.deso.com"}, + DisableDelegatedStake: false, + VotingPublicKey: votingPublicKey.ToString(), + VotingPublicKeySignature: votingSignature.ToString(), + ExtraData: extraData, + MinFeeRateNanosPerKB: apiServer.MinFeeRateNanosPerKB, + TransactionFees: []TransactionFee{}, + } + bodyJSON, err := json.Marshal(body) + require.NoError(t, err) + request, _ := http.NewRequest("POST", RoutePathValidators+"/register", bytes.NewBuffer(bodyJSON)) + request.Header.Set("Content-Type", "application/json") + response := httptest.NewRecorder() + apiServer.router.ServeHTTP(response, request) + require.NotContains(t, string(response.Body.Bytes()), "error") + + // Decode response. + decoder := json.NewDecoder(io.LimitReader(response.Body, MaxRequestBodySizeBytes)) + txnResponse := ValidatorTxnResponse{} + err = decoder.Decode(&txnResponse) + require.NoError(t, err) + + // Test response fields. + txn := txnResponse.Transaction + require.Equal(t, txn.PublicKey, senderPkBytes) + txnMeta := txn.TxnMeta.(*lib.RegisterAsValidatorMetadata) + require.Len(t, txnMeta.Domains, 2) + require.Equal(t, txnMeta.Domains[0], []byte("https://sender-001.deso.com")) + require.Equal(t, txnMeta.Domains[1], []byte("https://sender-002.deso.com")) + require.False(t, txnMeta.DisableDelegatedStake) + require.True(t, txnMeta.VotingPublicKey.Eq(votingPublicKey)) + require.True(t, txnMeta.VotingPublicKeySignature.Eq(votingSignature)) + extraDataEncoded, err := EncodeExtraDataMap(extraData) + require.NoError(t, err) + require.Equal(t, txn.ExtraData, extraDataEncoded) + + // Sign txn. + require.Nil(t, txn.Signature.Sign) + signTxn(t, txn, senderPrivString) + require.NotNil(t, txn.Signature.Sign) + + // Submit txn. + _, err = submitTxn(t, apiServer, txn) + require.NoError(t, err) + } + { + // sender unregisters as a validator. + + // Send POST request. + body := &UnregisterAsValidatorRequest{ + TransactorPublicKeyBase58Check: senderPkString, + ExtraData: map[string]string{}, + MinFeeRateNanosPerKB: apiServer.MinFeeRateNanosPerKB, + TransactionFees: []TransactionFee{}, + } + bodyJSON, err := json.Marshal(body) + require.NoError(t, err) + request, _ := http.NewRequest("POST", RoutePathValidators+"/unregister", bytes.NewBuffer(bodyJSON)) + request.Header.Set("Content-Type", "application/json") + response := httptest.NewRecorder() + apiServer.router.ServeHTTP(response, request) + require.NotContains(t, string(response.Body.Bytes()), "error") + + // Decode response. + decoder := json.NewDecoder(io.LimitReader(response.Body, MaxRequestBodySizeBytes)) + txnResponse := ValidatorTxnResponse{} + err = decoder.Decode(&txnResponse) + require.NoError(t, err) + + // Test response fields. + txn := txnResponse.Transaction + require.Equal(t, txn.PublicKey, senderPkBytes) + + // Sign txn. + require.Nil(t, txn.Signature.Sign) + signTxn(t, txn, senderPrivString) + require.NotNil(t, txn.Signature.Sign) + + // Submit txn. + _, err = submitTxn(t, apiServer, txn) + require.NoError(t, err) + } +} + +func _generateVotingPublicKeyAndSignature(t *testing.T, transactorPkBytes []byte) (*bls.PublicKey, *bls.Signature) { + blsPrivateKey, err := bls.NewPrivateKey() + require.NoError(t, err) + votingPublicKey := blsPrivateKey.PublicKey() + signaturePayload := lib.CreateValidatorVotingSignaturePayload(transactorPkBytes) + votingSignature, err := blsPrivateKey.Sign(signaturePayload) + require.NoError(t, err) + return votingPublicKey, votingSignature +} From cf62ed014d04ba40ae62a586b39fe2119872c9f3 Mon Sep 17 00:00:00 2001 From: mattfoley8 Date: Wed, 14 Jun 2023 12:30:03 -0400 Subject: [PATCH 08/84] Add relic dependency to prod dockerfile. --- Dockerfile | 12 +++++++++--- test.Dockerfile | 5 +++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index d7fec234..6c105e91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,10 @@ FROM alpine:latest AS backend RUN apk update RUN apk upgrade -RUN apk add --update go gcc g++ vips-dev +RUN apk add --update bash cmake g++ gcc git make vips-dev + +COPY --from=golang:1.20-alpine /usr/local/go/ /usr/local/go/ +ENV PATH="/usr/local/go/bin:${PATH}" WORKDIR /deso/src @@ -26,13 +29,16 @@ COPY backend/main.go . # include core src COPY core/bls ../core/bls -COPY core/desohash ../core/desohash COPY core/cmd ../core/cmd +COPY core/desohash ../core/desohash COPY core/lib ../core/lib COPY core/migrate ../core/migrate +COPY core/scripts ../core/scripts + +RUN ../core/scripts/install-relic.sh # build backend -RUN GOOS=linux go build -mod=mod -a -installsuffix cgo -o bin/backend main.go +RUN GOOS=linux go build -mod=mod -a -installsuffix cgo -o bin/backend -tags=relic main.go # create tiny image FROM alpine:latest diff --git a/test.Dockerfile b/test.Dockerfile index ce28ac59..785601c9 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -2,7 +2,7 @@ FROM alpine:latest AS backend RUN apk update RUN apk upgrade -RUN apk add --update bash cmake gcc g++ make vips-dev git +RUN apk add --update bash cmake g++ gcc git make vips-dev COPY --from=golang:1.20-alpine /usr/local/go/ /usr/local/go/ ENV PATH="/usr/local/go/bin:${PATH}" @@ -12,7 +12,8 @@ WORKDIR /deso/src RUN git clone https://github.com/deso-protocol/core.git WORKDIR /deso/src/core -RUN git checkout mf/add-bls-signature-utils && \ +RUN git pull && \ + git checkout mf/add-bls-signature-utils && \ git pull origin mf/add-bls-signature-utils # TODO: Revert to `git pull` once core PR is merged. RUN go mod download From 32e6c56e3ced3e9582f8a45b338000e80d21dde8 Mon Sep 17 00:00:00 2001 From: Matt Foley <100429827+mattfoley8@users.noreply.github.com> Date: Wed, 14 Jun 2023 17:22:37 -0400 Subject: [PATCH 09/84] Mf/add get validator by public key endpoint (#501) * Add get validator by PublicKey route. * Address PR review feedback. --- routes/server.go | 7 +++ routes/validators.go | 91 +++++++++++++++++++++++++++++++++++++++ routes/validators_test.go | 59 +++++++++++++++++++++---- 3 files changed, 149 insertions(+), 8 deletions(-) diff --git a/routes/server.go b/routes/server.go index 9dca3ef8..2aba5c9b 100644 --- a/routes/server.go +++ b/routes/server.go @@ -1287,6 +1287,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.UnregisterAsValidator, PublicAccess, }, + { + "GetValidatorByPublicKeyBase58Check", + []string{"GET"}, + RoutePathValidators + "/{publicKeyBase58Check:t?BC[1-9A-HJ-NP-Za-km-z]{51,53}}", + fes.GetValidatorByPublicKeyBase58Check, + PublicAccess, + }, // Jumio Routes { "JumioBegin", diff --git a/routes/validators.go b/routes/validators.go index e013ab35..c11d1280 100644 --- a/routes/validators.go +++ b/routes/validators.go @@ -6,6 +6,8 @@ import ( "fmt" "github.com/deso-protocol/core/bls" "github.com/deso-protocol/core/lib" + "github.com/gorilla/mux" + "github.com/holiman/uint256" "io" "net/http" ) @@ -38,6 +40,19 @@ type ValidatorTxnResponse struct { TxnHashHex string } +type ValidatorResponse struct { + ValidatorPublicKeyBase58Check string + Domains []string + DisableDelegatedStake bool + VotingPublicKey string + VotingPublicKeySignature string + TotalStakeAmountNanos *uint256.Int + Status string + LastActiveAtEpochNumber uint64 + JailedAtEpochNumber uint64 + ExtraData map[string]string +} + func (fes *APIServer) RegisterAsValidator(ww http.ResponseWriter, req *http.Request) { // Decode request body. decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) @@ -210,3 +225,79 @@ func (fes *APIServer) UnregisterAsValidator(ww http.ResponseWriter, req *http.Re return } } + +func (fes *APIServer) GetValidatorByPublicKeyBase58Check(ww http.ResponseWriter, req *http.Request) { + // Parse ValidatorPublicKeyBase58Check from URL. + vars := mux.Vars(req) + validatorPublicKeyBase58Check, exists := vars["publicKeyBase58Check"] + if !exists { + _AddBadRequestError(ww, "GetValidatorByPublicKeyBase58Check: must provide a ValidatorPublicKeyBase58Check") + return + } + + // Create UTXO view. + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddInternalServerError(ww, "GetValidatorByPublicKeyBase58Check: problem getting UTXO view") + return + } + + // Convert ValidatorPublicKeyBase58Check to ValidatorPKID. + validatorPKID, err := fes.getPKIDFromPublicKeyBase58Check(utxoView, validatorPublicKeyBase58Check) + if err != nil || validatorPKID == nil { + _AddInternalServerError(ww, "GetValidatorByPublicKeyBase58Check: problem retrieving validator PKID") + return + } + + // Get validator by PKID. + validatorEntry, err := utxoView.GetValidatorByPKID(validatorPKID) + if err != nil { + _AddInternalServerError(ww, "GetValidatorByPublicKeyBase58Check: problem retrieving validator") + return + } + if validatorEntry == nil { + _AddNotFoundError(ww, "GetValidatorByPublicKeyBase58Check: validator not found") + return + } + + // Encode response. + validatorResponse := _convertValidatorEntryToResponse(utxoView, validatorEntry, fes.Params) + if err = json.NewEncoder(ww).Encode(validatorResponse); err != nil { + _AddInternalServerError(ww, "GetValidatorByPublicKeyBase58Check: problem encoding response as JSON") + return + } +} + +func _convertValidatorEntryToResponse( + utxoView *lib.UtxoView, validatorEntry *lib.ValidatorEntry, params *lib.DeSoParams, +) *ValidatorResponse { + // Nil check: this should never happen but just to be safe. + if validatorEntry == nil { + return &ValidatorResponse{} + } + + // Convert ValidatorPKID to ValidatorPublicKeyBase58Check. + validatorPublicKeyBase58Check := lib.Base58CheckEncode( + utxoView.GetPublicKeyForPKID(validatorEntry.ValidatorPKID), false, params, + ) + + // Convert Domains [][]byte to []string. + var domains []string + for _, domain := range validatorEntry.Domains { + domains = append(domains, string(domain)) + } + + // Convert ValidatorEntry to ValidatorResponse. + return &ValidatorResponse{ + ValidatorPublicKeyBase58Check: validatorPublicKeyBase58Check, + Domains: domains, + DisableDelegatedStake: validatorEntry.DisableDelegatedStake, + VotingPublicKey: validatorEntry.VotingPublicKey.ToString(), + VotingPublicKeySignature: validatorEntry.VotingPublicKeySignature.ToString(), + TotalStakeAmountNanos: validatorEntry.TotalStakeAmountNanos.Clone(), + Status: validatorEntry.Status().ToString(), + LastActiveAtEpochNumber: validatorEntry.LastActiveAtEpochNumber, + JailedAtEpochNumber: validatorEntry.JailedAtEpochNumber, + ExtraData: DecodeExtraDataMap(params, utxoView, validatorEntry.ExtraData), + } +} diff --git a/routes/validators_test.go b/routes/validators_test.go index 9a56850e..8c99282c 100644 --- a/routes/validators_test.go +++ b/routes/validators_test.go @@ -21,19 +21,20 @@ func TestValidatorRegistration(t *testing.T) { senderPkBytes, _, err := lib.Base58CheckDecode(senderPkString) require.NoError(t, err) + // sender creates a VotingPublicKey and VotingSignature. + votingPublicKey, votingSignature := _generateVotingPublicKeyAndSignature(t, senderPkBytes) + { // sender registers as a validator. // Send POST request. - votingPublicKey, votingSignature := _generateVotingPublicKeyAndSignature(t, senderPkBytes) - extraData := map[string]string{"Foo": "Bar"} body := &RegisterAsValidatorRequest{ TransactorPublicKeyBase58Check: senderPkString, Domains: []string{"https://sender-001.deso.com", "https://sender-002.deso.com"}, DisableDelegatedStake: false, VotingPublicKey: votingPublicKey.ToString(), VotingPublicKeySignature: votingSignature.ToString(), - ExtraData: extraData, + ExtraData: map[string]string{"Foo": "Bar"}, MinFeeRateNanosPerKB: apiServer.MinFeeRateNanosPerKB, TransactionFees: []TransactionFee{}, } @@ -51,7 +52,7 @@ func TestValidatorRegistration(t *testing.T) { err = decoder.Decode(&txnResponse) require.NoError(t, err) - // Test response fields. + // Verify response fields. txn := txnResponse.Transaction require.Equal(t, txn.PublicKey, senderPkBytes) txnMeta := txn.TxnMeta.(*lib.RegisterAsValidatorMetadata) @@ -61,9 +62,8 @@ func TestValidatorRegistration(t *testing.T) { require.False(t, txnMeta.DisableDelegatedStake) require.True(t, txnMeta.VotingPublicKey.Eq(votingPublicKey)) require.True(t, txnMeta.VotingPublicKeySignature.Eq(votingSignature)) - extraDataEncoded, err := EncodeExtraDataMap(extraData) - require.NoError(t, err) - require.Equal(t, txn.ExtraData, extraDataEncoded) + require.NotNil(t, txn.ExtraData) + require.Equal(t, txn.ExtraData["Foo"], []byte("Bar")) // Sign txn. require.Nil(t, txn.Signature.Sign) @@ -74,6 +74,36 @@ func TestValidatorRegistration(t *testing.T) { _, err = submitTxn(t, apiServer, txn) require.NoError(t, err) } + { + // get sender validator by PublicKeyBase58Check + + // Send GET request. + request, _ := http.NewRequest("GET", RoutePathValidators+"/"+senderPkString, nil) + response := httptest.NewRecorder() + apiServer.router.ServeHTTP(response, request) + require.NotContains(t, string(response.Body.Bytes()), "error") + + // Decode response. + decoder := json.NewDecoder(io.LimitReader(response.Body, MaxRequestBodySizeBytes)) + validatorResponse := ValidatorResponse{} + err := decoder.Decode(&validatorResponse) + require.NoError(t, err) + + // Verify response fields. + require.Equal(t, validatorResponse.ValidatorPublicKeyBase58Check, senderPkString) + require.Len(t, validatorResponse.Domains, 2) + require.Equal(t, validatorResponse.Domains[0], "https://sender-001.deso.com") + require.Equal(t, validatorResponse.Domains[1], "https://sender-002.deso.com") + require.False(t, validatorResponse.DisableDelegatedStake) + require.Equal(t, validatorResponse.VotingPublicKey, votingPublicKey.ToString()) + require.Equal(t, validatorResponse.VotingPublicKeySignature, votingSignature.ToString()) + require.Equal(t, validatorResponse.TotalStakeAmountNanos.Uint64(), uint64(0)) + require.Equal(t, validatorResponse.Status, "Active") + require.Equal(t, validatorResponse.LastActiveAtEpochNumber, uint64(0)) + require.Equal(t, validatorResponse.JailedAtEpochNumber, uint64(0)) + require.NotNil(t, validatorResponse.ExtraData) + require.Equal(t, validatorResponse.ExtraData["Foo"], "Bar") + } { // sender unregisters as a validator. @@ -98,7 +128,7 @@ func TestValidatorRegistration(t *testing.T) { err = decoder.Decode(&txnResponse) require.NoError(t, err) - // Test response fields. + // Verify response fields. txn := txnResponse.Transaction require.Equal(t, txn.PublicKey, senderPkBytes) @@ -111,6 +141,19 @@ func TestValidatorRegistration(t *testing.T) { _, err = submitTxn(t, apiServer, txn) require.NoError(t, err) } + { + // get sender validator by PublicKeyBase58Check + + // Send GET request. + request, _ := http.NewRequest("GET", RoutePathValidators+"/"+senderPkString, nil) + response := httptest.NewRecorder() + apiServer.router.ServeHTTP(response, request) + responseBody := string(response.Body.Bytes()) + + // errors: doesn't exist + require.Contains(t, responseBody, "error") + require.Contains(t, responseBody, "validator not found") + } } func _generateVotingPublicKeyAndSignature(t *testing.T, transactorPkBytes []byte) (*bls.PublicKey, *bls.Signature) { From 1f88c5275bf03e1ea924cde7a2328ab10b47b416 Mon Sep 17 00:00:00 2001 From: Matt Foley <100429827+mattfoley8@users.noreply.github.com> Date: Thu, 15 Jun 2023 12:22:53 -0400 Subject: [PATCH 10/84] Rename VotingPublicKeySignature to VotingAuthorization. (#502) * Rename VotingPublicKeySignature to VotingAuthorization. * Checkout corresponding core branch. * Change core branch in test CI. --- routes/validators.go | 20 ++++++++++---------- routes/validators_test.go | 18 +++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/routes/validators.go b/routes/validators.go index c11d1280..687a668d 100644 --- a/routes/validators.go +++ b/routes/validators.go @@ -17,7 +17,7 @@ type RegisterAsValidatorRequest struct { Domains []string `safeForLogging:"true"` DisableDelegatedStake bool `safeForLogging:"true"` VotingPublicKey string `safeForLogging:"true"` - VotingPublicKeySignature string `safeForLogging:"true"` + VotingAuthorization string `safeForLogging:"true"` ExtraData map[string]string `safeForLogging:"true"` MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` TransactionFees []TransactionFee `safeForLogging:"true"` @@ -45,7 +45,7 @@ type ValidatorResponse struct { Domains []string DisableDelegatedStake bool VotingPublicKey string - VotingPublicKeySignature string + VotingAuthorization string TotalStakeAmountNanos *uint256.Int Status string LastActiveAtEpochNumber uint64 @@ -86,10 +86,10 @@ func (fes *APIServer) RegisterAsValidator(ww http.ResponseWriter, req *http.Requ return } - // Convert VotingPublicKeySignatureString to VotingPublicKeySignature. - votingPublicKeySignature, err := (&bls.Signature{}).FromString(requestData.VotingPublicKeySignature) + // Convert VotingAuthorizationString to VotingAuthorization. + votingAuthorization, err := (&bls.Signature{}).FromString(requestData.VotingAuthorization) if err != nil { - _AddBadRequestError(ww, "RegisterAsValidator: problem parsing VotingPublicKeySignature") + _AddBadRequestError(ww, "RegisterAsValidator: problem parsing VotingAuthorization") return } @@ -116,10 +116,10 @@ func (fes *APIServer) RegisterAsValidator(ww http.ResponseWriter, req *http.Requ txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateRegisterAsValidatorTxn( transactorPublicKeyBytes, &lib.RegisterAsValidatorMetadata{ - Domains: domains, - DisableDelegatedStake: requestData.DisableDelegatedStake, - VotingPublicKey: votingPublicKey, - VotingPublicKeySignature: votingPublicKeySignature, + Domains: domains, + DisableDelegatedStake: requestData.DisableDelegatedStake, + VotingPublicKey: votingPublicKey, + VotingAuthorization: votingAuthorization, }, extraData, requestData.MinFeeRateNanosPerKB, @@ -293,7 +293,7 @@ func _convertValidatorEntryToResponse( Domains: domains, DisableDelegatedStake: validatorEntry.DisableDelegatedStake, VotingPublicKey: validatorEntry.VotingPublicKey.ToString(), - VotingPublicKeySignature: validatorEntry.VotingPublicKeySignature.ToString(), + VotingAuthorization: validatorEntry.VotingAuthorization.ToString(), TotalStakeAmountNanos: validatorEntry.TotalStakeAmountNanos.Clone(), Status: validatorEntry.Status().ToString(), LastActiveAtEpochNumber: validatorEntry.LastActiveAtEpochNumber, diff --git a/routes/validators_test.go b/routes/validators_test.go index 8c99282c..be7188b8 100644 --- a/routes/validators_test.go +++ b/routes/validators_test.go @@ -21,8 +21,8 @@ func TestValidatorRegistration(t *testing.T) { senderPkBytes, _, err := lib.Base58CheckDecode(senderPkString) require.NoError(t, err) - // sender creates a VotingPublicKey and VotingSignature. - votingPublicKey, votingSignature := _generateVotingPublicKeyAndSignature(t, senderPkBytes) + // sender creates a VotingPublicKey and VotingAuthorization. + votingPublicKey, votingAuthorization := _generateVotingPublicKeyAndAuthorization(t, senderPkBytes) { // sender registers as a validator. @@ -33,7 +33,7 @@ func TestValidatorRegistration(t *testing.T) { Domains: []string{"https://sender-001.deso.com", "https://sender-002.deso.com"}, DisableDelegatedStake: false, VotingPublicKey: votingPublicKey.ToString(), - VotingPublicKeySignature: votingSignature.ToString(), + VotingAuthorization: votingAuthorization.ToString(), ExtraData: map[string]string{"Foo": "Bar"}, MinFeeRateNanosPerKB: apiServer.MinFeeRateNanosPerKB, TransactionFees: []TransactionFee{}, @@ -61,7 +61,7 @@ func TestValidatorRegistration(t *testing.T) { require.Equal(t, txnMeta.Domains[1], []byte("https://sender-002.deso.com")) require.False(t, txnMeta.DisableDelegatedStake) require.True(t, txnMeta.VotingPublicKey.Eq(votingPublicKey)) - require.True(t, txnMeta.VotingPublicKeySignature.Eq(votingSignature)) + require.True(t, txnMeta.VotingAuthorization.Eq(votingAuthorization)) require.NotNil(t, txn.ExtraData) require.Equal(t, txn.ExtraData["Foo"], []byte("Bar")) @@ -96,7 +96,7 @@ func TestValidatorRegistration(t *testing.T) { require.Equal(t, validatorResponse.Domains[1], "https://sender-002.deso.com") require.False(t, validatorResponse.DisableDelegatedStake) require.Equal(t, validatorResponse.VotingPublicKey, votingPublicKey.ToString()) - require.Equal(t, validatorResponse.VotingPublicKeySignature, votingSignature.ToString()) + require.Equal(t, validatorResponse.VotingAuthorization, votingAuthorization.ToString()) require.Equal(t, validatorResponse.TotalStakeAmountNanos.Uint64(), uint64(0)) require.Equal(t, validatorResponse.Status, "Active") require.Equal(t, validatorResponse.LastActiveAtEpochNumber, uint64(0)) @@ -156,12 +156,12 @@ func TestValidatorRegistration(t *testing.T) { } } -func _generateVotingPublicKeyAndSignature(t *testing.T, transactorPkBytes []byte) (*bls.PublicKey, *bls.Signature) { +func _generateVotingPublicKeyAndAuthorization(t *testing.T, transactorPkBytes []byte) (*bls.PublicKey, *bls.Signature) { blsPrivateKey, err := bls.NewPrivateKey() require.NoError(t, err) votingPublicKey := blsPrivateKey.PublicKey() - signaturePayload := lib.CreateValidatorVotingSignaturePayload(transactorPkBytes) - votingSignature, err := blsPrivateKey.Sign(signaturePayload) + votingAuthorizationPayload := lib.CreateValidatorVotingAuthorizationPayload(transactorPkBytes) + votingAuthorization, err := blsPrivateKey.Sign(votingAuthorizationPayload) require.NoError(t, err) - return votingPublicKey, votingSignature + return votingPublicKey, votingAuthorization } From a64baa625c1ecdb24e40aff8aecacc571fc34c59 Mon Sep 17 00:00:00 2001 From: Matt Foley <100429827+mattfoley8@users.noreply.github.com> Date: Mon, 19 Jun 2023 10:36:31 -0400 Subject: [PATCH 11/84] Refactor merging GlobalParamsEntry defaults. (#503) * Refactor merging GlobalParamsEntry defaults. * Change core branch in test dockerfile. --- routes/admin_transaction.go | 46 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/routes/admin_transaction.go b/routes/admin_transaction.go index 3643e759..0ae1d3ab 100644 --- a/routes/admin_transaction.go +++ b/routes/admin_transaction.go @@ -67,7 +67,7 @@ func (fes *APIServer) GetGlobalParams(ww http.ResponseWriter, req *http.Request) _AddBadRequestError(ww, fmt.Sprintf("GetGlobalParams: Error getting utxoView: %v", err)) return } - globalParamsEntry := utxoView.GlobalParamsEntry + globalParamsEntry := utxoView.GetCurrentGlobalParamsEntry() // Return all the data associated with the transaction in the response res := GetGlobalParamsResponse{ USDCentsPerBitcoin: globalParamsEntry.USDCentsPerBitcoin, @@ -75,11 +75,11 @@ func (fes *APIServer) GetGlobalParams(ww http.ResponseWriter, req *http.Request) MinimumNetworkFeeNanosPerKB: globalParamsEntry.MinimumNetworkFeeNanosPerKB, CreateNFTFeeNanos: globalParamsEntry.CreateNFTFeeNanos, MaxCopiesPerNFT: globalParamsEntry.MaxCopiesPerNFT, - StakeLockupEpochDuration: utxoView.GetCurrentGlobalParam(lib.StakeLockupEpochDuration), - ValidatorJailEpochDuration: utxoView.GetCurrentGlobalParam(lib.ValidatorJailEpochDuration), - LeaderScheduleMaxNumValidators: utxoView.GetCurrentGlobalParam(lib.LeaderScheduleMaxNumValidators), - EpochDurationNumBlocks: utxoView.GetCurrentGlobalParam(lib.EpochDurationNumBlocks), - JailInactiveValidatorGracePeriodEpochs: utxoView.GetCurrentGlobalParam(lib.JailInactiveValidatorGracePeriodEpochs), + StakeLockupEpochDuration: globalParamsEntry.StakeLockupEpochDuration, + ValidatorJailEpochDuration: globalParamsEntry.ValidatorJailEpochDuration, + LeaderScheduleMaxNumValidators: globalParamsEntry.LeaderScheduleMaxNumValidators, + EpochDurationNumBlocks: globalParamsEntry.EpochDurationNumBlocks, + JailInactiveValidatorGracePeriodEpochs: globalParamsEntry.JailInactiveValidatorGracePeriodEpochs, } if err := json.NewEncoder(ww).Encode(res); err != nil { _AddBadRequestError(ww, fmt.Sprintf("GetGlobalParams: Problem encoding response as JSON: %v", err)) @@ -190,30 +190,32 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque } // Only update values if they have changed. Values less than 0 are excluded from the transaction + globalParamsEntry := utxoView.GetCurrentGlobalParamsEntry() + usdCentsPerBitcoin := int64(-1) - if requestData.USDCentsPerBitcoin >= 0 && uint64(requestData.USDCentsPerBitcoin) != utxoView.GlobalParamsEntry.USDCentsPerBitcoin { + if requestData.USDCentsPerBitcoin >= 0 && uint64(requestData.USDCentsPerBitcoin) != globalParamsEntry.USDCentsPerBitcoin { usdCentsPerBitcoin = requestData.USDCentsPerBitcoin } createProfileFeeNanos := int64(-1) - if requestData.CreateProfileFeeNanos >= 0 && uint64(requestData.CreateProfileFeeNanos) != utxoView.GlobalParamsEntry.CreateProfileFeeNanos { + if requestData.CreateProfileFeeNanos >= 0 && uint64(requestData.CreateProfileFeeNanos) != globalParamsEntry.CreateProfileFeeNanos { createProfileFeeNanos = requestData.CreateProfileFeeNanos } createNFTFeeNanos := int64(-1) - if requestData.CreateNFTFeeNanos >= 0 && uint64(requestData.CreateNFTFeeNanos) != utxoView.GlobalParamsEntry.CreateNFTFeeNanos { + if requestData.CreateNFTFeeNanos >= 0 && uint64(requestData.CreateNFTFeeNanos) != globalParamsEntry.CreateNFTFeeNanos { createNFTFeeNanos = requestData.CreateNFTFeeNanos } minimumNetworkFeeNanosPerKb := int64(-1) - if requestData.MinimumNetworkFeeNanosPerKB >= 0 && uint64(requestData.MinimumNetworkFeeNanosPerKB) != utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB { + if requestData.MinimumNetworkFeeNanosPerKB >= 0 && uint64(requestData.MinimumNetworkFeeNanosPerKB) != globalParamsEntry.MinimumNetworkFeeNanosPerKB { minimumNetworkFeeNanosPerKb = requestData.MinimumNetworkFeeNanosPerKB } maxCopiesPerNFT := int64(-1) - if requestData.MaxCopiesPerNFT >= 0 && uint64(requestData.MaxCopiesPerNFT) != utxoView.GlobalParamsEntry.MaxCopiesPerNFT { + if requestData.MaxCopiesPerNFT >= 0 && uint64(requestData.MaxCopiesPerNFT) != globalParamsEntry.MaxCopiesPerNFT { maxCopiesPerNFT = requestData.MaxCopiesPerNFT } maxNonceExpirationBlockHeightOffset := int64(-1) - if requestData.MaxNonceExpirationBlockHeightOffset >= 0 && uint64(requestData.MaxNonceExpirationBlockHeightOffset) != utxoView.GlobalParamsEntry.MaxNonceExpirationBlockHeightOffset { + if requestData.MaxNonceExpirationBlockHeightOffset >= 0 && uint64(requestData.MaxNonceExpirationBlockHeightOffset) != globalParamsEntry.MaxNonceExpirationBlockHeightOffset { maxNonceExpirationBlockHeightOffset = requestData.MaxNonceExpirationBlockHeightOffset } @@ -221,28 +223,28 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque // Update Proof of Stake consensus related global params if they have changed. if requestData.StakeLockupEpochDuration > 0 && - requestData.StakeLockupEpochDuration != utxoView.GetCurrentGlobalParam(lib.StakeLockupEpochDuration) { - extraData[lib.StakeLockupEpochDuration.ToString()] = lib.UintToBuf(requestData.StakeLockupEpochDuration) + requestData.StakeLockupEpochDuration != globalParamsEntry.StakeLockupEpochDuration { + extraData[lib.StakeLockupEpochDurationKey] = lib.UintToBuf(requestData.StakeLockupEpochDuration) } if requestData.ValidatorJailEpochDuration > 0 && - requestData.ValidatorJailEpochDuration != utxoView.GetCurrentGlobalParam(lib.ValidatorJailEpochDuration) { - extraData[lib.ValidatorJailEpochDuration.ToString()] = lib.UintToBuf(requestData.ValidatorJailEpochDuration) + requestData.ValidatorJailEpochDuration != globalParamsEntry.ValidatorJailEpochDuration { + extraData[lib.ValidatorJailEpochDurationKey] = lib.UintToBuf(requestData.ValidatorJailEpochDuration) } if requestData.LeaderScheduleMaxNumValidators > 0 && - requestData.LeaderScheduleMaxNumValidators != utxoView.GetCurrentGlobalParam(lib.LeaderScheduleMaxNumValidators) { - extraData[lib.LeaderScheduleMaxNumValidators.ToString()] = lib.UintToBuf(requestData.LeaderScheduleMaxNumValidators) + requestData.LeaderScheduleMaxNumValidators != globalParamsEntry.LeaderScheduleMaxNumValidators { + extraData[lib.LeaderScheduleMaxNumValidatorsKey] = lib.UintToBuf(requestData.LeaderScheduleMaxNumValidators) } if requestData.EpochDurationNumBlocks > 0 && - requestData.EpochDurationNumBlocks != utxoView.GetCurrentGlobalParam(lib.EpochDurationNumBlocks) { - extraData[lib.EpochDurationNumBlocks.ToString()] = lib.UintToBuf(requestData.EpochDurationNumBlocks) + requestData.EpochDurationNumBlocks != globalParamsEntry.EpochDurationNumBlocks { + extraData[lib.EpochDurationNumBlocksKey] = lib.UintToBuf(requestData.EpochDurationNumBlocks) } if requestData.JailInactiveValidatorGracePeriodEpochs > 0 && - requestData.JailInactiveValidatorGracePeriodEpochs != utxoView.GetCurrentGlobalParam(lib.JailInactiveValidatorGracePeriodEpochs) { - extraData[lib.JailInactiveValidatorGracePeriodEpochs.ToString()] = lib.UintToBuf(requestData.JailInactiveValidatorGracePeriodEpochs) + requestData.JailInactiveValidatorGracePeriodEpochs != globalParamsEntry.JailInactiveValidatorGracePeriodEpochs { + extraData[lib.JailInactiveValidatorGracePeriodEpochsKey] = lib.UintToBuf(requestData.JailInactiveValidatorGracePeriodEpochs) } // Try and create the update txn for the user. From ea9c5d5ff0657d4cc01ec10e9476928de57700be Mon Sep 17 00:00:00 2001 From: Matt Foley <100429827+mattfoley8@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:46:48 -0400 Subject: [PATCH 12/84] Update test.Dockerfile core branch. (#504) --- test.Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.Dockerfile b/test.Dockerfile index 37a281c3..a1ed5cd2 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -13,8 +13,8 @@ RUN git clone https://github.com/deso-protocol/core.git WORKDIR /deso/src/core RUN git pull && \ - git checkout mf/pos-merge-20230605 && \ - git pull origin mf/pos-merge-20230605 # TODO: Revert to `git pull` once core PR is merged. + git checkout feature/proof-of-stake && \ + git pull origin feature/proof-of-stake # TODO: Revert to `git pull` once core PR is merged. RUN go mod download RUN ./scripts/install-relic.sh From c40453c849f93a55c6ee48f59372eabb245fabf7 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Mon, 4 Dec 2023 22:10:44 -0500 Subject: [PATCH 13/84] Initial backend updates to conform to new function signatures in core (#512) Co-authored-by: Lazy Nina <> --- Dockerfile | 14 ++-- go.mod | 1 + go.sum | 2 + routes/access_group_test.go | 2 +- routes/admin_node.go | 4 +- routes/admin_transaction.go | 14 ++++ routes/admin_transaction_test.go | 3 + routes/exchange.go | 4 +- routes/exchange_test.go | 112 ++----------------------------- routes/global_state_test.go | 6 +- routes/miner.go | 2 +- routes/transaction.go | 1 + 12 files changed, 43 insertions(+), 122 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6c105e91..24721308 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,12 +28,14 @@ COPY backend/countries countries COPY backend/main.go . # include core src -COPY core/bls ../core/bls -COPY core/cmd ../core/cmd -COPY core/desohash ../core/desohash -COPY core/lib ../core/lib -COPY core/migrate ../core/migrate -COPY core/scripts ../core/scripts +COPY core/bls ../core/bls +COPY core/cmd ../core/cmd +COPY core/collections ../core/collections +COPY core/consensus ../core/consensus +COPY core/desohash ../core/desohash +COPY core/lib ../core/lib +COPY core/migrate ../core/migrate +COPY core/scripts ../core/scripts RUN ../core/scripts/install-relic.sh diff --git a/go.mod b/go.mod index b4b79c8d..1c351627 100644 --- a/go.mod +++ b/go.mod @@ -53,6 +53,7 @@ require ( github.com/deso-protocol/go-merkle-tree v1.0.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dustin/go-humanize v1.0.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/ethereum/go-ethereum v1.9.25 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect diff --git a/go.sum b/go.sum index 3dbb5e5e..75f51c55 100644 --- a/go.sum +++ b/go.sum @@ -164,6 +164,8 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= diff --git a/routes/access_group_test.go b/routes/access_group_test.go index 11d5d535..ef058388 100644 --- a/routes/access_group_test.go +++ b/routes/access_group_test.go @@ -97,7 +97,7 @@ func ExecuteRequest(t *testing.T, apiServer *APIServer, routePath string, reques func TestAPIAccessGroupBaseGroupMembership(t *testing.T) { assert := assert.New(t) - apiServer, _, _ := newTestAPIServer(t, "" /*globalStateRemoteNode*/) + apiServer, _, _ := newTestAPIServer(t, "" /*globalStateRemoteNode*/, false) // form the request for RoutePathGetAllUserAccessGroups values := GetAccessGroupsRequest{PublicKeyBase58Check: senderPkString} diff --git a/routes/admin_node.go b/routes/admin_node.go index f1ebc32f..473c26dd 100644 --- a/routes/admin_node.go +++ b/routes/admin_node.go @@ -109,13 +109,13 @@ func (fes *APIServer) _handleNodeControlGetInfo( { desoNodeStatus.LatestHeaderHeight = desoHeaderTip.Height desoNodeStatus.LatestHeaderHash = hex.EncodeToString(desoHeaderTip.Hash[:]) - desoNodeStatus.LatestHeaderTstampSecs = uint32(desoHeaderTip.Header.TstampSecs) + desoNodeStatus.LatestHeaderTstampSecs = uint32(desoHeaderTip.Header.GetTstampSecs()) } // Main block chain fields { desoNodeStatus.LatestBlockHeight = desoBlockTip.Height desoNodeStatus.LatestBlockHash = hex.EncodeToString(desoBlockTip.Hash[:]) - desoNodeStatus.LatestBlockTstampSecs = uint32(desoBlockTip.Header.TstampSecs) + desoNodeStatus.LatestBlockTstampSecs = uint32(desoBlockTip.Header.GetTstampSecs()) } if fes.TXIndex != nil { // TxIndex status diff --git a/routes/admin_transaction.go b/routes/admin_transaction.go index 0ae1d3ab..4f6bbceb 100644 --- a/routes/admin_transaction.go +++ b/routes/admin_transaction.go @@ -44,6 +44,10 @@ type GetGlobalParamsResponse struct { // are included when generating a new Proof-of-Stake leader schedule. LeaderScheduleMaxNumValidators uint64 `safeForLogging:"true"` + // ValidatorSetMaxNumValidators is the maximum number of validators that + // are included when generating a new Proof-of-Stake validator set. + ValidatorSetMaxNumValidators uint64 `safeForLogging:"true"` + // EpochDurationNumBlocks is the number of blocks included in one epoch. EpochDurationNumBlocks uint64 `safeForLogging:"true"` @@ -78,6 +82,7 @@ func (fes *APIServer) GetGlobalParams(ww http.ResponseWriter, req *http.Request) StakeLockupEpochDuration: globalParamsEntry.StakeLockupEpochDuration, ValidatorJailEpochDuration: globalParamsEntry.ValidatorJailEpochDuration, LeaderScheduleMaxNumValidators: globalParamsEntry.LeaderScheduleMaxNumValidators, + ValidatorSetMaxNumValidators: globalParamsEntry.ValidatorSetMaxNumValidators, EpochDurationNumBlocks: globalParamsEntry.EpochDurationNumBlocks, JailInactiveValidatorGracePeriodEpochs: globalParamsEntry.JailInactiveValidatorGracePeriodEpochs, } @@ -121,6 +126,10 @@ type UpdateGlobalParamsRequest struct { // are included when generating a new Proof-of-Stake leader schedule. LeaderScheduleMaxNumValidators uint64 `safeForLogging:"true"` + // ValidatorSetMaxNumValidators is the maximum number of validators that + // are included when generating a new Proof-of-Stake validator set. + ValidatorSetMaxNumValidators uint64 `safeForLogging:"true"` + // EpochDurationNumBlocks is the number of blocks included in one epoch. EpochDurationNumBlocks uint64 `safeForLogging:"true"` @@ -237,6 +246,11 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque extraData[lib.LeaderScheduleMaxNumValidatorsKey] = lib.UintToBuf(requestData.LeaderScheduleMaxNumValidators) } + if requestData.ValidatorSetMaxNumValidators > 0 && + requestData.ValidatorSetMaxNumValidators != globalParamsEntry.ValidatorSetMaxNumValidators { + extraData[lib.ValidatorSetMaxNumValidatorsKey] = lib.UintToBuf(requestData.ValidatorSetMaxNumValidators) + } + if requestData.EpochDurationNumBlocks > 0 && requestData.EpochDurationNumBlocks != globalParamsEntry.EpochDurationNumBlocks { extraData[lib.EpochDurationNumBlocksKey] = lib.UintToBuf(requestData.EpochDurationNumBlocks) diff --git a/routes/admin_transaction_test.go b/routes/admin_transaction_test.go index 06d67f7f..0d195822 100644 --- a/routes/admin_transaction_test.go +++ b/routes/admin_transaction_test.go @@ -100,6 +100,7 @@ func TestUpdateGlobalParams(t *testing.T) { StakeLockupEpochDuration: 4, ValidatorJailEpochDuration: 4, LeaderScheduleMaxNumValidators: 101, + ValidatorSetMaxNumValidators: 102, EpochDurationNumBlocks: 3601, JailInactiveValidatorGracePeriodEpochs: 49, MinFeeRateNanosPerKB: 99, @@ -112,6 +113,7 @@ func TestUpdateGlobalParams(t *testing.T) { require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(4)) require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(4)) require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(101)) + require.Equal(t, globalParams.ValidatorSetMaxNumValidators, uint64(102)) require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(3601)) require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(49)) } @@ -131,6 +133,7 @@ func TestUpdateGlobalParams(t *testing.T) { require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(4)) require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(4)) require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(101)) + require.Equal(t, globalParams.ValidatorSetMaxNumValidators, uint64(102)) require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(3601)) require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(50)) } diff --git a/routes/exchange.go b/routes/exchange.go index 89eba7f5..30f54311 100644 --- a/routes/exchange.go +++ b/routes/exchange.go @@ -132,7 +132,7 @@ func _headerToResponse(header *lib.MsgDeSoHeader, hash string) *HeaderResponse { Version: header.Version, PrevBlockHashHex: header.PrevBlockHash.String(), TransactionMerkleRootHex: header.TransactionMerkleRoot.String(), - TstampSecs: header.TstampSecs, + TstampSecs: header.GetTstampSecs(), Height: header.Height, Nonce: header.Nonce, ExtraNonce: header.ExtraNonce, @@ -666,7 +666,7 @@ func APITransactionToResponse( if block != nil && block.Header != nil { ret.BlockInfo = &TransactionBlockInfo{ Height: block.Header.Height, - TimestampSecs: block.Header.TstampSecs, + TimestampSecs: block.Header.GetTstampSecs(), } } diff --git a/routes/exchange_test.go b/routes/exchange_test.go index 663ce57c..2756e059 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -4,8 +4,9 @@ import ( "bytes" "encoding/hex" "encoding/json" - chainlib "github.com/btcsuite/btcd/blockchain" + "github.com/deso-protocol/backend/config" coreCmd "github.com/deso-protocol/core/cmd" + "github.com/deso-protocol/core/lib" "github.com/google/uuid" "io" "io/ioutil" @@ -14,10 +15,6 @@ import ( "net/http/httptest" "os" "testing" - "time" - - "github.com/deso-protocol/backend/config" - "github.com/deso-protocol/core/lib" "github.com/dgraph-io/badger/v3" @@ -78,106 +75,7 @@ func GetTestBadgerDb(t *testing.T) (_db *badger.DB, _dir string) { return db, dir } -func NewLowDifficultyBlockchain(t *testing.T) (*lib.Blockchain, *lib.DeSoParams, *badger.DB, string) { - - // Set the number of txns per view regeneration to one while creating the txns - lib.ReadOnlyUtxoViewRegenerationIntervalTxns = 1 - - return NewLowDifficultyBlockchainWithParams(t, &lib.DeSoTestnetParams) -} - -func NewLowDifficultyBlockchainWithParams(t *testing.T, params *lib.DeSoParams) ( - *lib.Blockchain, *lib.DeSoParams, *badger.DB, string) { - - // Set the number of txns per view regeneration to one while creating the txns - lib.ReadOnlyUtxoViewRegenerationIntervalTxns = 1 - - db, dir := GetTestBadgerDb(t) - timesource := chainlib.NewMedianTime() - - // Set some special parameters for testing. If the blocks above are changed - // these values should be updated to reflect the latest testnet values. - paramsCopy := *params - paramsCopy.GenesisBlock = &lib.MsgDeSoBlock{ - Header: &lib.MsgDeSoHeader{ - Version: 0, - PrevBlockHash: lib.MustDecodeHexBlockHash("0000000000000000000000000000000000000000000000000000000000000000"), - TransactionMerkleRoot: lib.MustDecodeHexBlockHash("097158f0d27e6d10565c4dc696c784652c3380e0ff8382d3599a4d18b782e965"), - TstampSecs: uint64(1560735050), - Height: uint64(0), - Nonce: uint64(0), - // No ExtraNonce is set in the genesis block - }, - Txns: []*lib.MsgDeSoTxn{ - { - TxInputs: []*lib.DeSoInput{}, - TxOutputs: []*lib.DeSoOutput{}, - TxnMeta: &lib.BlockRewardMetadataa{ - ExtraData: []byte("They came here, to the new world. World 2.0, version 1776."), - }, - // A signature is not required for BLOCK_REWARD transactions since they - // don't spend anything. - }, - }, - } - paramsCopy.MinDifficultyTargetHex = "999999948931e5874cf66a74c0fda790dd8c7458243d400324511a4c71f54faa" - paramsCopy.MinChainWorkHex = "0000000000000000000000000000000000000000000000000000000000000000" - paramsCopy.MiningIterationsPerCycle = 500 - // Set maturity to 2 blocks so we can test spending on short chains. The - // tests rely on the maturity equaling exactly two blocks (i.e. being - // two times the time between blocks). - paramsCopy.TimeBetweenBlocks = 2 * time.Second - paramsCopy.BlockRewardMaturity = time.Second * 4 - paramsCopy.TimeBetweenDifficultyRetargets = 100 * time.Second - paramsCopy.MaxDifficultyRetargetFactor = 2 - paramsCopy.SeedBalances = []*lib.DeSoOutput{ - { - PublicKey: lib.MustBase58CheckDecode(moneyPkString), - AmountNanos: uint64(2000000 * lib.NanosPerUnit), - }, - } - - // Temporarily modify the seed balances to make a specific public - // key have some DeSo - chain, err := lib.NewBlockchain([]string{blockSignerPk}, 0, 0, - ¶msCopy, timesource, db, nil, nil, nil, false) - if err != nil { - log.Fatal(err) - } - - return chain, ¶msCopy, db, dir -} - -func NewTestMiner(t *testing.T, chain *lib.Blockchain, params *lib.DeSoParams, isSender bool) (*lib.DeSoMempool, *lib.DeSoMiner) { - assert := assert.New(t) - require := require.New(t) - _ = assert - _ = require - - mempool := lib.NewDeSoMempool( - chain, 0, /* rateLimitFeeRateNanosPerKB */ - 0 /* minFeeRateNanosPerKB */, "", true, - "" /*dataDir*/, "") - minerPubKeys := []string{} - if isSender { - minerPubKeys = append(minerPubKeys, senderPkString) - } else { - minerPubKeys = append(minerPubKeys, recipientPkString) - } - - blockProducer, err := lib.NewDeSoBlockProducer( - 0, 1, - blockSignerSeed, - mempool, chain, - params, nil) - require.NoError(err) - - newMiner, err := lib.NewDeSoMiner(minerPubKeys, 1 /*numThreads*/, blockProducer, params) - require.NoError(err) - return mempool, newMiner -} - -func newTestAPIServer(t *testing.T, globalStateRemoteNode string) (*APIServer, *APIServer, *lib.DeSoMiner) { +func newTestAPIServer(t *testing.T, globalStateRemoteNode string, txindex bool) (*APIServer, *APIServer, *lib.DeSoMiner) { assert := assert.New(t) require := require.New(t) _, _ = assert, require @@ -202,7 +100,7 @@ func newTestAPIServer(t *testing.T, globalStateRemoteNode string) (*APIServer, * coreConfig := coreCmd.LoadConfig() coreConfig.Params = &lib.DeSoTestnetParams coreConfig.DataDirectory = badgerDir - coreConfig.TXIndex = true + coreConfig.TXIndex = txindex coreConfig.MinerPublicKeys = []string{senderPkString} coreConfig.NumMiningThreads = 1 coreConfig.HyperSync = false @@ -257,7 +155,7 @@ func TestAPI(t *testing.T) { require := require.New(t) _, _ = assert, require - apiServer, _, miner := newTestAPIServer(t, "" /*globalStateRemoteNode*/) + apiServer, _, miner := newTestAPIServer(t, "" /*globalStateRemoteNode*/, false) { request, _ := http.NewRequest("GET", RoutePathAPIBase, nil) diff --git a/routes/global_state_test.go b/routes/global_state_test.go index 235b829c..cea0e1c8 100644 --- a/routes/global_state_test.go +++ b/routes/global_state_test.go @@ -18,7 +18,7 @@ func TestGlobalStateServicePutGetDeleteWithDB(t *testing.T) { _, _ = assert, require apiServer, _, _ := newTestAPIServer( - t, "" /*globalStateRemoteNode*/) + t, "" /*globalStateRemoteNode*/, false) // Getting when no value is present should return nil without an // error. @@ -62,7 +62,7 @@ func TestGlobalStateServicePutGetDeleteWithRemoteNode(t *testing.T) { _, _ = assert, require apiServer, _, _ := newTestAPIServer( - t, "" /*globalStateRemoteNode*/) + t, "" /*globalStateRemoteNode*/, false) // Getting when no value is present should return nil without an // error. @@ -189,7 +189,7 @@ func TestGlobalStateServiceURLCreation(t *testing.T) { _, _ = assert, require apiServer, _, _ := newTestAPIServer( - t, "https://deso.com:17001" /*globalStateRemoteNode*/) + t, "https://deso.com:17001" /*globalStateRemoteNode*/, false) { url, _, err := apiServer.GlobalState.CreateGetRequest([]byte("woo")) diff --git a/routes/miner.go b/routes/miner.go index 4f046bc9..752b5655 100644 --- a/routes/miner.go +++ b/routes/miner.go @@ -187,7 +187,7 @@ func (fes *APIServer) SubmitBlock(ww http.ResponseWriter, req *http.Request) { // TODO: Signature checking slows things down because it acquires the ChainLock. // The optimal solution is to check signatures in a way that doesn't acquire the // ChainLock, which is what Bitcoin Core does. - isMainChain, isOrphan, err := fes.blockchain.ProcessBlock( + isMainChain, isOrphan, _, err := fes.blockchain.ProcessBlock( blockFound, true /*verifySignatures*/) glog.V(1).Infof("Called ProcessBlock: isMainChain=(%v), isOrphan=(%v), err=(%v)", isMainChain, isOrphan, err) diff --git a/routes/transaction.go b/routes/transaction.go index 43ee242a..6405f370 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -3953,6 +3953,7 @@ func (fes *APIServer) simulateSubmitTransaction(utxoView *lib.UtxoView, txn *lib txn.Hash(), 0, bestHeight, + 0, false, false, ) From f045518391941afef30bfa3645d771f5587a12e0 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:40:34 -0500 Subject: [PATCH 14/84] Update backend to use BackendMempool interface instead of DeSoMempool (#513) Co-authored-by: Lazy Nina <> --- go.mod | 2 +- routes/exchange.go | 18 +++++++----------- routes/exchange_test.go | 14 ++++++-------- routes/hot_feed.go | 2 +- routes/server.go | 4 ++-- routes/user.go | 5 +---- 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index 1c351627..4c9a0578 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,6 @@ require ( github.com/fatih/structs v1.1.0 github.com/golang-jwt/jwt/v4 v4.1.0 github.com/golang/glog v1.0.0 - github.com/google/uuid v1.2.0 github.com/gorilla/mux v1.8.0 github.com/h2non/bimg v1.1.5 github.com/holiman/uint256 v1.1.1 @@ -68,6 +67,7 @@ require ( github.com/golang/snappy v0.0.3 // indirect github.com/google/flatbuffers v2.0.0+incompatible // indirect github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 // indirect + github.com/google/uuid v1.2.0 // indirect github.com/googleapis/gax-go/v2 v2.0.5 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.8 // indirect diff --git a/routes/exchange.go b/routes/exchange.go index 30f54311..a5f0259d 100644 --- a/routes/exchange.go +++ b/routes/exchange.go @@ -133,6 +133,7 @@ func _headerToResponse(header *lib.MsgDeSoHeader, hash string) *HeaderResponse { PrevBlockHashHex: header.PrevBlockHash.String(), TransactionMerkleRootHex: header.TransactionMerkleRoot.String(), TstampSecs: header.GetTstampSecs(), + TstampNanoSecs: header.TstampNanoSecs, Height: header.Height, Nonce: header.Nonce, ExtraNonce: header.ExtraNonce, @@ -968,11 +969,7 @@ func (fes *APIServer) APITransactionInfo(ww http.ResponseWriter, rr *http.Reques // IsMempool means we should just return all of the transactions that are currently in the mempool. if transactionInfoRequest.IsMempool { // Get all the txns from the mempool. - poolTxns, _, err := fes.mempool.GetTransactionsOrderedByTimeAdded() - if err != nil { - APIAddError(ww, fmt.Sprintf("APITransactionInfo: Error getting txns from mempool: %v", err)) - return - } + poolTxns := fes.mempool.GetOrderedTransactions() res := &APITransactionInfoResponse{} res.Transactions = []*TransactionResponse{} @@ -1039,7 +1036,7 @@ func (fes *APIServer) APITransactionInfo(ww http.ResponseWriter, rr *http.Reques if txn == nil { // Try to look the transaction up in the mempool before giving up. - txnInPool := fes.mempool.GetTransaction(txID) + txnInPool := fes.mempool.GetMempoolTx(txID) if txnInPool == nil { APIAddError(ww, fmt.Sprintf("APITransactionInfo: Could not find transaction with TransactionIDBase58Check = %s", transactionInfoRequest.TransactionIDBase58Check)) @@ -1154,11 +1151,7 @@ func (fes *APIServer) APITransactionInfo(ww http.ResponseWriter, rr *http.Reques if transactionInfoRequest.LastPublicKeyTransactionIndex <= 0 { // Start with the mempool - poolTxns, _, err := fes.mempool.GetTransactionsOrderedByTimeAdded() - if err != nil { - APIAddError(ww, fmt.Sprintf("APITransactionInfo: Error getting txns from mempool: %v", err)) - return - } + poolTxns := fes.mempool.GetOrderedTransactions() // Go from most recent to least recent // TODO: Support pagination for mempool transactions @@ -1270,6 +1263,9 @@ type HeaderResponse struct { // The unix timestamp (in seconds) specifying when this block was // mined. TstampSecs uint64 + // The unix timestamp (in nanoseconds) specifying when this block was + // mined. + TstampNanoSecs uint64 // The height of the block this header corresponds to. Height uint64 diff --git a/routes/exchange_test.go b/routes/exchange_test.go index 2756e059..94518e99 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -7,9 +7,7 @@ import ( "github.com/deso-protocol/backend/config" coreCmd "github.com/deso-protocol/core/cmd" "github.com/deso-protocol/core/lib" - "github.com/google/uuid" "io" - "io/ioutil" "log" "net/http" "net/http/httptest" @@ -54,7 +52,7 @@ func CleanUpBadger(db *badger.DB) { } func GetTestBadgerDb(t *testing.T) (_db *badger.DB, _dir string) { - dir, err := ioutil.TempDir("", "badgerdb-"+uuid.New().String()) + dir, err := os.MkdirTemp("", "badgerdb") if err != nil { log.Fatal(err) } @@ -135,9 +133,9 @@ func newTestAPIServer(t *testing.T, globalStateRemoteNode string, txindex bool) privateApiServer.initState() miner := node.Server.GetMiner() - _, err = miner.MineAndProcessSingleBlock(0, node.Server.GetMempool()) + _, err = miner.MineAndProcessSingleBlock(0, node.Server.GetMempool().(*lib.DeSoMempool)) require.NoError(err) - _, err = miner.MineAndProcessSingleBlock(0, node.Server.GetMempool()) + _, err = miner.MineAndProcessSingleBlock(0, node.Server.GetMempool().(*lib.DeSoMempool)) require.NoError(err) t.Cleanup(func() { @@ -664,7 +662,7 @@ func TestAPI(t *testing.T) { txn1 := &lib.MsgDeSoTxn{} txn1Bytes, _ := hex.DecodeString(txn1Hex) _ = txn1.FromBytes(txn1Bytes) - _, err := apiServer.mempool.ProcessTransaction( + _, err := apiServer.mempool.(*lib.DeSoMempool).ProcessTransaction( txn1, false /*allowOrphan*/, true /*rateLimit*/, 0, /*peerID*/ true /*verifySignatures*/) require.NoError(err) @@ -779,7 +777,7 @@ func TestAPI(t *testing.T) { txn2 := &lib.MsgDeSoTxn{} txn2Bytes, _ := hex.DecodeString(txn2Hex) _ = txn2.FromBytes(txn2Bytes) - apiServer.mempool.ProcessTransaction( + apiServer.mempool.(*lib.DeSoMempool).ProcessTransaction( txn2, false /*allowOrphan*/, true /*rateLimit*/, 0, /*peerID*/ true /*verifySignatures*/) { @@ -961,7 +959,7 @@ func TestAPI(t *testing.T) { } // Mine a block and check the balances. - block3, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, apiServer.mempool) + block3, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, apiServer.mempool.(*lib.DeSoMempool)) require.NoError(err) balSum := int64(0) { diff --git a/routes/hot_feed.go b/routes/hot_feed.go index 0f058b2e..853cfc87 100644 --- a/routes/hot_feed.go +++ b/routes/hot_feed.go @@ -446,7 +446,7 @@ func (fes *APIServer) UpdateHotFeedOrderedList( // Create new "block" for mempool txns, give it a block age of 1 greater than the current tip // First get all MempoolTxns from mempool. - mempoolTxnsOrderedByTime, _, err := fes.backendServer.GetMempool().GetTransactionsOrderedByTimeAdded() + mempoolTxnsOrderedByTime := fes.backendServer.GetMempool().GetOrderedTransactions() // Extract MsgDesoTxn from each MempoolTxn var txnsFromMempoolOrderedByTime []*lib.MsgDeSoTxn for _, mempoolTxn := range mempoolTxnsOrderedByTime { diff --git a/routes/server.go b/routes/server.go index 2aba5c9b..7c46af86 100644 --- a/routes/server.go +++ b/routes/server.go @@ -321,7 +321,7 @@ const ( // frontend cares about, from posts to profiles to purchasing DeSo with Bitcoin. type APIServer struct { backendServer *lib.Server - mempool *lib.DeSoMempool + mempool lib.Mempool blockchain *lib.Blockchain blockProducer *lib.DeSoBlockProducer Params *lib.DeSoParams @@ -475,7 +475,7 @@ type LastTradePriceHistoryItem struct { // NewAPIServer ... func NewAPIServer( _backendServer *lib.Server, - _mempool *lib.DeSoMempool, + _mempool lib.Mempool, _blockchain *lib.Blockchain, _blockProducer *lib.DeSoBlockProducer, txIndex *lib.TXIndex, diff --git a/routes/user.go b/routes/user.go index 5e6863aa..a38ec364 100644 --- a/routes/user.go +++ b/routes/user.go @@ -2535,10 +2535,7 @@ func (fes *APIServer) _getMempoolNotifications(request *GetNotificationsRequest, // // TODO(performance): This could get slow if the mempool gets big. Fix is to organize everything // in the mempool by public key and only look up transactions that are relevant to this public key. - poolTxns, _, err := fes.mempool.GetTransactionsOrderedByTimeAdded() - if err != nil { - return nil, errors.Errorf("APITransactionInfo: Error getting txns from mempool: %v", err) - } + poolTxns := fes.mempool.GetOrderedTransactions() mempoolTxnMetadata := []*TransactionMetadataResponse{} for _, poolTx := range poolTxns { From f3932da21612f2333ab01e0581e43f0f11d24592 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Wed, 13 Dec 2023 12:51:10 -0500 Subject: [PATCH 15/84] Add fee estimator arg to all txn construction calls (#514) Co-authored-by: Lazy Nina <> --- routes/access_group.go | 6 ++++-- routes/admin_transaction.go | 4 ++-- routes/associations.go | 4 ++++ routes/exchange.go | 4 ++-- routes/message.go | 6 ++++-- routes/new_message.go | 11 ++++++----- routes/nft.go | 21 +++++++++++++------- routes/shared.go | 3 ++- routes/transaction.go | 39 ++++++++++++++++++++++++------------- routes/validators.go | 2 ++ 10 files changed, 66 insertions(+), 34 deletions(-) diff --git a/routes/access_group.go b/routes/access_group.go index 6a5b7278..873f3d01 100644 --- a/routes/access_group.go +++ b/routes/access_group.go @@ -117,7 +117,8 @@ func (fes *APIServer) accessGroupHandler( accessGroupOwnerPkBytes, accessGroupPkBytes, accessGroupKeyNameBytes, accessGroupOperationType, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { return fmt.Errorf("problem creating transaction: %v", err) } @@ -397,7 +398,8 @@ func (fes *APIServer) accessGroupMemberHandler( accessGroupOwnerPkBytes, accessGroupKeyNameBytes, accessGroupMembers, accessGroupMemberOperationType, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { return fmt.Errorf("problem creating transaction: %v", err) } diff --git a/routes/admin_transaction.go b/routes/admin_transaction.go index 4f6bbceb..7b2f5277 100644 --- a/routes/admin_transaction.go +++ b/routes/admin_transaction.go @@ -273,7 +273,7 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque maxNonceExpirationBlockHeightOffset, extraData, requestData.MinFeeRateNanosPerKB, - fes.backendServer.GetMempool(), additionalOutputs) + fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateGlobalParams: Problem creating transaction: %v", err)) return @@ -401,7 +401,7 @@ func (fes *APIServer) SwapIdentity(ww http.ResponseWriter, req *http.Request) { toPublicKey, requestData.MinFeeRateNanosPerKB, - fes.backendServer.GetMempool(), additionalOutputs) + fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SwapIdentity: Problem creating transaction: %v", err)) return diff --git a/routes/associations.go b/routes/associations.go index 14c9f9b7..23f88b5e 100644 --- a/routes/associations.go +++ b/routes/associations.go @@ -252,6 +252,7 @@ func (fes *APIServer) CreateUserAssociation(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("CreateUserAssociation: problem creating txn: %v", err)) @@ -337,6 +338,7 @@ func (fes *APIServer) DeleteUserAssociation(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("DeleteUserAssociation: problem creating txn: %v", err)) @@ -804,6 +806,7 @@ func (fes *APIServer) CreatePostAssociation(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("CreatePostAssociation: problem creating txn: %v", err)) @@ -889,6 +892,7 @@ func (fes *APIServer) DeletePostAssociation(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("DeletePostAssociation: problem creating txn: %v", err)) diff --git a/routes/exchange.go b/routes/exchange.go index a5f0259d..84a99649 100644 --- a/routes/exchange.go +++ b/routes/exchange.go @@ -766,7 +766,7 @@ func (fes *APIServer) APITransferDeSo(ww http.ResponseWriter, rr *http.Request) txnn, totalInputt, spendAmountt, feeNanoss, err = fes.blockchain.CreateMaxSpend( senderPublicKeyBytes, recipientPub.SerializeCompressed(), uint64(minFeeRateNanosPerKB), - fes.backendServer.GetMempool(), additionalOutputs) + fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) if err != nil { APIAddError(ww, fmt.Sprintf("APITransferDeSo: Error processing MAX transaction: %v", err)) return @@ -1423,7 +1423,7 @@ func (fes *APIServer) _augmentAndProcessTransactionWithSubsidyWithKey( // return an error. totalInput, spendAmount, changeAmount, fees, err := fes.blockchain.AddInputsAndChangeToTransactionWithSubsidy(txn, minFeeRateNanosPerKB, - inputSubsidy, fes.mempool, 0) + inputSubsidy, fes.mempool, 0, fes.backendServer.GetFeeEstimator()) if err != nil { return 0, 0, 0, 0, fmt.Errorf("_augmentAndProcessTransactionWithKey: Problem adding inputs and "+ "change to transaction %v: %v", txn, err) diff --git a/routes/message.go b/routes/message.go index e30f75a8..8f150d4b 100644 --- a/routes/message.go +++ b/routes/message.go @@ -714,7 +714,8 @@ func (fes *APIServer) SendMessageStateless(ww http.ResponseWriter, req *http.Req senderMessagingPublicKey, senderMessagingGroupKeyNameBytes, recipientMessagingPublicKey, recipientMessagingGroupKeyNameBytes, tstamp, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendMessageStateless: Problem creating transaction: %v", err)) return @@ -973,7 +974,8 @@ func (fes *APIServer) RegisterMessagingGroupKey(ww http.ResponseWriter, req *htt txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateMessagingKeyTxn( ownerPkBytes, messagingPkBytes, messagingKeyNameBytes, messagingKeySignature, []*lib.MessagingGroupMember{}, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("RegisterMessagingGroupKey: Problem creating transaction: %v", err)) return diff --git a/routes/new_message.go b/routes/new_message.go index f33d09f5..c428c382 100644 --- a/routes/new_message.go +++ b/routes/new_message.go @@ -372,11 +372,12 @@ func (fes *APIServer) sendMessageHandler( // Call CreateNewMessageTxn the core lib to construct the transaction to send a group chat message. // The message type must be lib.NewMessageTypeGroupChat, and operation type is lib.NewMessageOperationCreate. txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateNewMessageTxn( - senderGroupOwnerPkBytes, *lib.NewPublicKey(senderGroupOwnerPkBytes), *lib.NewGroupKeyName(senderGroupKeyNameBytes), *lib.NewPublicKey(senderAccessGroupPkbytes), - *lib.NewPublicKey(recipientGroupOwnerPkBytes), *lib.NewGroupKeyName(recipientGroupKeyNameBytes), *lib.NewPublicKey(recipientAccessGroupPkbytes), - hexDecodedEncryptedMessageBytes, tstamp, - newMessageType, newMessageOperationType, - extraData, requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + senderGroupOwnerPkBytes, *lib.NewPublicKey(senderGroupOwnerPkBytes), + *lib.NewGroupKeyName(senderGroupKeyNameBytes), *lib.NewPublicKey(senderAccessGroupPkbytes), + *lib.NewPublicKey(recipientGroupOwnerPkBytes), *lib.NewGroupKeyName(recipientGroupKeyNameBytes), + *lib.NewPublicKey(recipientAccessGroupPkbytes), hexDecodedEncryptedMessageBytes, tstamp, + newMessageType, newMessageOperationType, extraData, requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) if err != nil { return errors.Wrapf(err, "Problem creating transaction: ") } diff --git a/routes/nft.go b/routes/nft.go index c6affae5..d730d16b 100644 --- a/routes/nft.go +++ b/routes/nft.go @@ -262,7 +262,8 @@ func (fes *APIServer) CreateNFT(ww http.ResponseWriter, req *http.Request) { additionalDESORoyaltiesPubKeyMap, additionalCoinRoyaltiesPubKeyMap, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateNFT: Problem creating transaction: %v", err)) return @@ -411,7 +412,8 @@ func (fes *APIServer) UpdateNFT(ww http.ResponseWriter, req *http.Request) { uint64(requestData.MinBidAmountNanos), requestData.IsBuyNow, requestData.BuyNowPriceNanos, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateNFT: Problem creating transaction: %v", err)) return @@ -568,7 +570,8 @@ func (fes *APIServer) CreateNFTBid(ww http.ResponseWriter, req *http.Request) { nftPostHash, uint64(requestData.SerialNumber), uint64(requestData.BidAmountNanos), - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateNFTBid: Problem creating transaction: %v", err)) return @@ -731,7 +734,8 @@ func (fes *APIServer) AcceptNFTBid(ww http.ResponseWriter, req *http.Request) { bidderPKID.PKID, uint64(requestData.BidAmountNanos), encryptedUnlockableTextBytes, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AcceptNFTBid: Problem creating transaction: %v", err)) return @@ -1649,7 +1653,8 @@ func (fes *APIServer) TransferNFT(ww http.ResponseWriter, req *http.Request) { nftPostHash, uint64(requestData.SerialNumber), []byte(requestData.EncryptedUnlockableText), - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferNFT: Problem creating transaction: %v", err)) return @@ -1789,7 +1794,8 @@ func (fes *APIServer) AcceptNFTTransfer(ww http.ResponseWriter, req *http.Reques updaterPublicKeyBytes, nftPostHash, uint64(requestData.SerialNumber), - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AcceptNFTTransfer: Problem creating transaction: %v", err)) return @@ -1928,7 +1934,8 @@ func (fes *APIServer) BurnNFT(ww http.ResponseWriter, req *http.Request) { updaterPublicKeyBytes, nftPostHash, uint64(requestData.SerialNumber), - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("BurnNFT: Problem creating transaction: %v", err)) return diff --git a/routes/shared.go b/routes/shared.go index c050007c..2a82de51 100644 --- a/routes/shared.go +++ b/routes/shared.go @@ -397,7 +397,8 @@ func (fes *APIServer) SendSeedDeSo(recipientPkBytes []byte, amountNanos uint64, if utxoView.GlobalParamsEntry != nil && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB > 0 { minFee = utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB } - _, _, _, _, err = fes.blockchain.AddInputsAndChangeToTransaction(txn, minFee, fes.mempool) + _, _, _, _, err = fes.blockchain.AddInputsAndChangeToTransaction(txn, minFee, fes.mempool, + fes.backendServer.GetFeeEstimator()) if err != nil { return nil, fmt.Errorf("SendSeedDeSo: Error adding inputs for seed DeSo: %v", err) } diff --git a/routes/transaction.go b/routes/transaction.go index 6405f370..b3355b50 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -409,7 +409,8 @@ func (fes *APIServer) UpdateProfile(ww http.ResponseWriter, req *http.Request) { requestData.IsHidden, additionalFees, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Problem creating transaction: %v", err)) return @@ -1069,7 +1070,7 @@ func (fes *APIServer) SendDeSo(ww http.ResponseWriter, req *http.Request) { // Create a MAX transaction txnn, totalInputt, spendAmountt, feeNanoss, err = fes.blockchain.CreateMaxSpend( senderPkBytes, recipientPkBytes, requestData.MinFeeRateNanosPerKB, - fes.backendServer.GetMempool(), additionalOutputs) + fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDeSo: Error processing MAX transaction: %v", err)) return @@ -1103,7 +1104,8 @@ func (fes *APIServer) SendDeSo(ww http.ResponseWriter, req *http.Request) { // depending on what the user requested. totalInputt, spendAmountt, changeAmountt, feeNanoss, err = fes.blockchain.AddInputsAndChangeToTransaction( - txnn, requestData.MinFeeRateNanosPerKB, fes.mempool) + txnn, requestData.MinFeeRateNanosPerKB, fes.mempool, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDeSo: Error processing transaction: %v", err)) return @@ -1212,7 +1214,8 @@ func (fes *APIServer) CreateLikeStateless(ww http.ResponseWriter, req *http.Requ // Try and create the message for the user. txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateLikeTxn( readerPkBytes, postHash, requestData.IsUnlike, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateLikeStateless: Problem creating transaction: %v", err)) return @@ -1462,7 +1465,8 @@ func (fes *APIServer) SubmitPost(ww http.ResponseWriter, req *http.Request) { tstamp, postExtraData, requestData.IsHidden, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SubmitPost: Problem creating transaction: %v", err)) return @@ -1615,7 +1619,8 @@ func (fes *APIServer) CreateFollowTxnStateless(ww http.ResponseWriter, req *http // Try and create the follow for the user. txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateFollowTxn( followerPkBytes, followedPkBytes, requestData.IsUnfollow, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateFollowTxnStateless: Problem creating transaction: %v", err)) return @@ -1789,7 +1794,8 @@ func (fes *APIServer) BuyOrSellCreatorCoin(ww http.ResponseWriter, req *http.Req requestData.MinDeSoExpectedNanos, requestData.MinCreatorCoinExpectedNanos, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("BuyOrSellCreatorCoin: Problem adding inputs and change transaction: %v", err)) return @@ -2053,7 +2059,8 @@ func (fes *APIServer) TransferCreatorCoin(ww http.ResponseWriter, req *http.Requ requestData.CreatorCoinToTransferNanos, receiverPublicKeyBytes, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferCreatorCoin: Problem creating transaction: %v", err)) return @@ -2195,7 +2202,8 @@ func (fes *APIServer) SendDiamonds(ww http.ResponseWriter, req *http.Request) { diamondPostHash, requestData.DiamondLevel, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDiamonds: Problem creating transaction: %v", err)) return @@ -2214,7 +2222,8 @@ func (fes *APIServer) SendDiamonds(ww http.ResponseWriter, req *http.Request) { diamondPostHash, requestData.DiamondLevel, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDiamonds: Problem creating transaction: %v", err)) return @@ -2436,7 +2445,8 @@ func (fes *APIServer) DAOCoin(ww http.ResponseWriter, req *http.Request) { TransferRestrictionStatus: transferRestrictionStatus, }, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("DAOCoin: Problem adding inputs and change transaction: %v", err)) return @@ -2571,7 +2581,8 @@ func (fes *APIServer) TransferDAOCoin(ww http.ResponseWriter, req *http.Request) DAOCoinToTransferNanos: requestData.DAOCoinToTransferNanos, }, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferDAOCoin: Problem creating transaction: %v", err)) return @@ -3126,6 +3137,7 @@ func (fes *APIServer) createDAOCoinLimitOrderResponse( minFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator(), ) if err != nil { @@ -3372,7 +3384,8 @@ func (fes *APIServer) AuthorizeDerivedKey(ww http.ResponseWriter, req *http.Requ memo, requestData.TransactionSpendingLimitHex, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AuthorizeDerivedKey: Problem creating transaction: %v", err)) return diff --git a/routes/validators.go b/routes/validators.go index 687a668d..5ac46603 100644 --- a/routes/validators.go +++ b/routes/validators.go @@ -125,6 +125,7 @@ func (fes *APIServer) RegisterAsValidator(ww http.ResponseWriter, req *http.Requ requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("RegisterAsValidator: problem creating txn: %v", err)) @@ -199,6 +200,7 @@ func (fes *APIServer) UnregisterAsValidator(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, + fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("UnregisterAsValidator: problem creating txn: %v", err)) From 4bf1f10f7f6ad730a711e393d5fc601b33604424 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:30:00 -0500 Subject: [PATCH 16/84] merge main into feature pos (#519) * [stable] Release 3.4.4 * add node version endpoint (#505) Co-authored-by: Lazy Nina <> * [stable] Release 3.4.5 * hotfix to exchange test * Add captcha verification (#509) * Updates to captcha verification * Updates to backend * Updates to captcha verify * Update captcha verification * Cleanup logs * Add routes to store reward amount in global state, track usage via data dog * Update verify captcha validation ordering, add back comp profile config bool * Update badger sync settings to optimize memory usage during hypersync (#506) * Update hypersync to use default badger settings, switch to performance settings once hypersync completes * Update test dockerfile to accept core branch name as parameter * Blank commit to trigger build * ln/fix-transaction-info-mempool (#510) Co-authored-by: Lazy Nina <> * ln/no-comp-when-0-create-profile-fee (#511) Co-authored-by: Lazy Nina <> * Empty commit to trigger build (#515) * Add extra data to basic transfer and diamond txn construction endpoints (#516) * trigger build (#517) Co-authored-by: Lazy Nina <> * trigger build * Add RWLock around AllCountryLevelSignUpBonuses (#518) Co-authored-by: Lazy Nina <> --------- Co-authored-by: Lazy Nina <> Co-authored-by: superzordon <88362450+superzordon@users.noreply.github.com> --- cmd/run.go | 1 + config/config.go | 6 + routes/admin_jumio.go | 6 + routes/base.go | 7 + routes/exchange.go | 30 +++- routes/exchange_test.go | 101 ++++++++++- routes/global_state.go | 17 +- routes/hot_feed.go | 24 ++- routes/server.go | 44 ++++- routes/supply.go | 5 + routes/transaction.go | 56 ++++-- routes/verify.go | 210 ++++++++++++++++++++++- scripts/nodes/n0 | 1 + scripts/nodes/n0_test | 3 +- scripts/tools/clear_ancestral_records.go | 2 +- test.Dockerfile | 6 + 16 files changed, 489 insertions(+), 30 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index aeac0335..02486a57 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -177,6 +177,7 @@ func init() { runCmd.PersistentFlags().String("metamask-airdrop-eth-minimum", "100000000000000", "In Wei, amount of Eth required to receive an airdrop during Metamask signup.") runCmd.PersistentFlags().Uint64("metamask-airdrop-deso-nanos-amount", 0, "Amount of DESO in nanos to send to metamask users as an airdrop") + runCmd.PersistentFlags().String("hcaptcha-secret", "", "Secret key for hcaptcha service. Used to verify captcha token verifications.") runCmd.PersistentFlags().VisitAll(func(flag *pflag.Flag) { viper.BindPFlag(flag.Name, flag) }) diff --git a/config/config.go b/config/config.go index 55ecc326..81b9b47a 100644 --- a/config/config.go +++ b/config/config.go @@ -94,6 +94,9 @@ type Config struct { MetamaskAirdropEthMinimum *uint256.Int // Amount of DESO in nanos metamask users receive as an airdrop MetamaskAirdropDESONanosAmount uint64 + + // Secret used to validate hCaptcha tokens. + HCaptchaSecret string } func LoadConfig(coreConfig *coreCmd.Config) *Config { @@ -194,6 +197,9 @@ func LoadConfig(coreConfig *coreCmd.Config) *Config { // Node source ID config.NodeSource = viper.GetUint64("node-source") + // hCaptcha secret + config.HCaptchaSecret = viper.GetString("hcaptcha-secret") + // Public keys that need their balances monitored. Map of Label to Public key labelsToPublicKeys := viper.GetString("public-key-balances-to-monitor") if len(labelsToPublicKeys) > 0 { diff --git a/routes/admin_jumio.go b/routes/admin_jumio.go index adfe40dc..cab84dbf 100644 --- a/routes/admin_jumio.go +++ b/routes/admin_jumio.go @@ -341,6 +341,8 @@ type GetAllCountryLevelSignUpBonusResponse struct { } func (fes *APIServer) AdminGetAllCountryLevelSignUpBonuses(ww http.ResponseWriter, req *http.Request) { + fes.allCountryLevelSignUpBonusesLock.RLock() + defer fes.allCountryLevelSignUpBonusesLock.RUnlock() res := GetAllCountryLevelSignUpBonusResponse{ SignUpBonusMetadata: fes.AllCountryLevelSignUpBonuses, DefaultSignUpBonusMetadata: fes.GetDefaultJumioCountrySignUpBonus(), @@ -373,6 +375,8 @@ func (fes *APIServer) SetAllCountrySignUpBonusMetadata() { // SetSingleCountrySignUpBonus sets the sign up bonus configuration for a given country in the cached map. func (fes *APIServer) SetSingleCountrySignUpBonus(countryDetails countries.Alpha3CountryCodeDetails, signUpBonus CountryLevelSignUpBonus) { + fes.allCountryLevelSignUpBonusesLock.Lock() + defer fes.allCountryLevelSignUpBonusesLock.Unlock() fes.AllCountryLevelSignUpBonuses[countryDetails.Name] = CountrySignUpBonusResponse{ CountryLevelSignUpBonus: signUpBonus, CountryCodeDetails: countryDetails, @@ -385,6 +389,8 @@ func (fes *APIServer) GetSingleCountrySignUpBonus(countryCode string) CountryLev countryCodeDetails := countries.Alpha3CountryCodes[strings.ToUpper(countryCode)] // If we can't find the signup bonus from the map, return the default. Else, return the sign up bonus we found in // the map. + fes.allCountryLevelSignUpBonusesLock.RLock() + defer fes.allCountryLevelSignUpBonusesLock.RUnlock() if countrySignUpBonusResponse, exists := fes.AllCountryLevelSignUpBonuses[countryCodeDetails.Name]; !exists { return fes.GetDefaultJumioCountrySignUpBonus() } else { diff --git a/routes/base.go b/routes/base.go index 8649c30e..59d6555e 100644 --- a/routes/base.go +++ b/routes/base.go @@ -358,6 +358,7 @@ type GetAppStateResponse struct { JumioKickbackUSDCents uint64 // CountrySignUpBonus is the sign-up bonus configuration for the country inferred from a request's IP address. CountrySignUpBonus CountryLevelSignUpBonus + CaptchaDeSoNanos uint64 DefaultFeeRateNanosPerKB uint64 TransactionFeeMap map[string][]TransactionFee @@ -394,6 +395,11 @@ func (fes *APIServer) GetAppState(ww http.ResponseWriter, req *http.Request) { defaultFeeRateNanosPerKB = globalParams.MinimumNetworkFeeNanosPerKB } + captchaDesoNanos, err := fes.getCaptchaRewardNanosFromGlobalState() + if err != nil { + captchaDesoNanos = 0 + } + res := &GetAppStateResponse{ MinSatoshisBurnedForProfileCreation: fes.Config.MinSatoshisForProfile, BlockHeight: fes.backendServer.GetBlockchain().BlockTip().Height, @@ -417,6 +423,7 @@ func (fes *APIServer) GetAppState(ww http.ResponseWriter, req *http.Request) { TransactionFeeMap: fes.TxnFeeMapToResponse(true), BuyETHAddress: fes.Config.BuyDESOETHAddress, Nodes: lib.NODES, + CaptchaDeSoNanos: captchaDesoNanos, // Deprecated USDCentsPerBitCloutExchangeRate: fes.GetExchangeDeSoPrice(), diff --git a/routes/exchange.go b/routes/exchange.go index 84a99649..a65cdb88 100644 --- a/routes/exchange.go +++ b/routes/exchange.go @@ -31,6 +31,8 @@ var ( IsBlacklisted = []byte{1} ) +const NodeVersion = "3.4.5" + const ( // RoutePathAPIBase ... RoutePathAPIBase = "/api/v1" @@ -46,6 +48,8 @@ const ( RoutePathAPINodeInfo = "/api/v1/node-info" // RoutePathAPIBlock ... RoutePathAPIBlock = "/api/v1/block" + // RoutePathAPINodeVersion ... + RoutePathAPINodeVersion = "/api/v1/node-version" ) // APIRoutes returns the routes for the public-facing API. @@ -100,6 +104,13 @@ func (fes *APIServer) APIRoutes() []Route { fes.APIBlock, PublicAccess, }, + { + "APINodeVersion", + []string{"GET"}, + RoutePathAPINodeVersion, + fes.APINodeVersion, + PublicAccess, + }, } return APIRoutes @@ -764,7 +775,7 @@ func (fes *APIServer) APITransferDeSo(ww http.ResponseWriter, rr *http.Request) if transferDeSoRequest.AmountNanos < 0 { // Create a MAX transaction txnn, totalInputt, spendAmountt, feeNanoss, err = fes.blockchain.CreateMaxSpend( - senderPublicKeyBytes, recipientPub.SerializeCompressed(), + senderPublicKeyBytes, recipientPub.SerializeCompressed(), nil, uint64(minFeeRateNanosPerKB), fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) if err != nil { @@ -1169,7 +1180,7 @@ func (fes *APIServer) APITransactionInfo(ww http.ResponseWriter, rr *http.Reques } // Skip irrelevant transactions - if !isRelevantTxn { + if !isRelevantTxn && txnMeta.TransactorPublicKeyBase58Check != transactionInfoRequest.PublicKeyBase58Check { continue } @@ -1369,6 +1380,21 @@ func (fes *APIServer) APIBlock(ww http.ResponseWriter, rr *http.Request) { } } +type APINodeVersionResponse struct { + Version string +} + +// APINodeVersion returns the version of the node. +func (fes *APIServer) APINodeVersion(ww http.ResponseWriter, rr *http.Request) { + if err := json.NewEncoder(ww).Encode(&APINodeVersionResponse{ + Version: NodeVersion, + }); err != nil { + APIAddError(ww, fmt.Sprintf("APINodeVersion: Problem encoding response "+ + "as JSON: %v", err)) + return + } +} + // TODO: This is a somewhat redundant version of processTransaction It exists // because the API needed to cut out the derivation of the public key from the // user object, among other things. diff --git a/routes/exchange_test.go b/routes/exchange_test.go index 94518e99..c14592cd 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -73,7 +73,106 @@ func GetTestBadgerDb(t *testing.T) (_db *badger.DB, _dir string) { return db, dir } -func newTestAPIServer(t *testing.T, globalStateRemoteNode string, txindex bool) (*APIServer, *APIServer, *lib.DeSoMiner) { +func NewLowDifficultyBlockchain(t *testing.T) (*lib.Blockchain, *lib.DeSoParams, *badger.DB, string) { + + // Set the number of txns per view regeneration to one while creating the txns + lib.ReadOnlyUtxoViewRegenerationIntervalTxns = 1 + + return NewLowDifficultyBlockchainWithParams(t, &lib.DeSoTestnetParams) +} + +func NewLowDifficultyBlockchainWithParams(t *testing.T, params *lib.DeSoParams) ( + *lib.Blockchain, *lib.DeSoParams, *badger.DB, string) { + + // Set the number of txns per view regeneration to one while creating the txns + lib.ReadOnlyUtxoViewRegenerationIntervalTxns = 1 + + db, dir := GetTestBadgerDb(t) + timesource := chainlib.NewMedianTime() + + // Set some special parameters for testing. If the blocks above are changed + // these values should be updated to reflect the latest testnet values. + paramsCopy := *params + paramsCopy.GenesisBlock = &lib.MsgDeSoBlock{ + Header: &lib.MsgDeSoHeader{ + Version: 0, + PrevBlockHash: lib.MustDecodeHexBlockHash("0000000000000000000000000000000000000000000000000000000000000000"), + TransactionMerkleRoot: lib.MustDecodeHexBlockHash("097158f0d27e6d10565c4dc696c784652c3380e0ff8382d3599a4d18b782e965"), + TstampSecs: uint64(1560735050), + Height: uint64(0), + Nonce: uint64(0), + // No ExtraNonce is set in the genesis block + }, + Txns: []*lib.MsgDeSoTxn{ + { + TxInputs: []*lib.DeSoInput{}, + TxOutputs: []*lib.DeSoOutput{}, + TxnMeta: &lib.BlockRewardMetadataa{ + ExtraData: []byte("They came here, to the new world. World 2.0, version 1776."), + }, + // A signature is not required for BLOCK_REWARD transactions since they + // don't spend anything. + }, + }, + } + paramsCopy.MinDifficultyTargetHex = "999999948931e5874cf66a74c0fda790dd8c7458243d400324511a4c71f54faa" + paramsCopy.MinChainWorkHex = "0000000000000000000000000000000000000000000000000000000000000000" + paramsCopy.MiningIterationsPerCycle = 500 + // Set maturity to 2 blocks so we can test spending on short chains. The + // tests rely on the maturity equaling exactly two blocks (i.e. being + // two times the time between blocks). + paramsCopy.TimeBetweenBlocks = 2 * time.Second + paramsCopy.BlockRewardMaturity = time.Second * 4 + paramsCopy.TimeBetweenDifficultyRetargets = 100 * time.Second + paramsCopy.MaxDifficultyRetargetFactor = 2 + paramsCopy.SeedBalances = []*lib.DeSoOutput{ + { + PublicKey: lib.MustBase58CheckDecode(moneyPkString), + AmountNanos: uint64(2000000 * lib.NanosPerUnit), + }, + } + + // Temporarily modify the seed balances to make a specific public + // key have some DeSo + chain, err := lib.NewBlockchain([]string{blockSignerPk}, 0, 0, + ¶msCopy, timesource, db, nil, nil, nil, false) + if err != nil { + log.Fatal(err) + } + + return chain, ¶msCopy, db, dir +} + +func NewTestMiner(t *testing.T, chain *lib.Blockchain, params *lib.DeSoParams, isSender bool) (*lib.DeSoMempool, *lib.DeSoMiner) { + assert := assert.New(t) + require := require.New(t) + _ = assert + _ = require + + mempool := lib.NewDeSoMempool( + chain, 0, /* rateLimitFeeRateNanosPerKB */ + 0 /* minFeeRateNanosPerKB */, "", true, + "" /*dataDir*/, "", true) + minerPubKeys := []string{} + if isSender { + minerPubKeys = append(minerPubKeys, senderPkString) + } else { + minerPubKeys = append(minerPubKeys, recipientPkString) + } + + blockProducer, err := lib.NewDeSoBlockProducer( + 0, 1, + blockSignerSeed, + mempool, chain, + params, nil) + require.NoError(err) + + newMiner, err := lib.NewDeSoMiner(minerPubKeys, 1 /*numThreads*/, blockProducer, params) + require.NoError(err) + return mempool, newMiner +} + +func newTestAPIServer(t *testing.T, globalStateRemoteNode string) (*APIServer, *APIServer, *lib.DeSoMiner) { assert := assert.New(t) require := require.New(t) _, _ = assert, require diff --git a/routes/global_state.go b/routes/global_state.go index 88c88acc..c478695c 100644 --- a/routes/global_state.go +++ b/routes/global_state.go @@ -240,8 +240,11 @@ var ( // -> _GlobalStatePrefixUsernameToBlacklistState = []byte{47} - // NEXT_TAG: 48 + // The prefix for modifying the starter nanos reward for solving a captcha on signup. + // -> + _GlobalStatePrefixToCaptchaReward = []byte{48} + // NEXT_TAG: 49 ) type HotFeedApprovedPostOp struct { @@ -389,6 +392,12 @@ type UserMetadata struct { UnreadNotifications uint64 // The most recently scanned notification transaction index in the database. Stored in order to prevent unnecessary re-scanning. LatestUnreadNotificationIndex int64 + + // The last block height that the user has submitted hcaptcha verification for. + LastHcaptchaBlockHeight uint32 + // HcaptchaShouldCompProfileCreation = True if we should comp the create profile fee because the user went through the + // Captcha flow. + HcaptchaShouldCompProfileCreation bool } type TutorialStatus string @@ -673,6 +682,12 @@ func GlobalStateKeyForBlacklistedProfileByUsername(username string) []byte { return key } +// Key for accessing the captcha reward amount. +func GlobalStateKeyForCaptchaRewardAmountNanos() []byte { + key := append([]byte{}, _GlobalStatePrefixToCaptchaReward...) + return key +} + // Key for accessing the blacklist audit logs associated with a user. func GlobalStateKeyForBlacklistAuditLogs(username string) []byte { key := append([]byte{}, _GlobalStatePrefixBlacklistAuditLog...) diff --git a/routes/hot_feed.go b/routes/hot_feed.go index 853cfc87..9a884efa 100644 --- a/routes/hot_feed.go +++ b/routes/hot_feed.go @@ -83,13 +83,23 @@ func (fes *APIServer) StartHotFeedRoutine() { for { select { case <-time.After(30 * time.Second): - resetCache := false - if cacheResetCounter >= ResetCachesIterationLimit { - resetCache = true - cacheResetCounter = 0 - } - fes.UpdateHotFeed(resetCache) - cacheResetCounter += 1 + // Use an inner function to unlock the mutex with a defer statement. + func() { + // If we're syncing a snapshot, we need to lock the DB mutex before updating the hot feed. + // This is because at the end of a snapshot sync, we re-start the DB, which will cause + // the hot feed routine to panic if it's in the middle of updating the hot feed. + if fes.backendServer.GetBlockchain().ChainState() == lib.SyncStateSyncingSnapshot { + fes.backendServer.DbMutex.Lock() + defer fes.backendServer.DbMutex.Unlock() + } + resetCache := false + if cacheResetCounter >= ResetCachesIterationLimit { + resetCache = true + cacheResetCounter = 0 + } + fes.UpdateHotFeed(resetCache) + cacheResetCounter += 1 + }() case <-fes.quit: break out } diff --git a/routes/server.go b/routes/server.go index 7c46af86..710a0d4c 100644 --- a/routes/server.go +++ b/routes/server.go @@ -155,10 +155,12 @@ const ( RoutePathSubmitPhoneNumberVerificationCode = "/api/v0/submit-phone-number-verification-code" RoutePathResendVerifyEmail = "/api/v0/resend-verify-email" RoutePathVerifyEmail = "/api/v0/verify-email" + RoutePathVerifyCaptcha = "/api/v0/verify-captcha" RoutePathJumioBegin = "/api/v0/jumio-begin" RoutePathJumioCallback = "/api/v0/jumio-callback" RoutePathJumioFlowFinished = "/api/v0/jumio-flow-finished" RoutePathGetJumioStatusForPublicKey = "/api/v0/get-jumio-status-for-public-key" + RoutePathAdminSetCaptchaRewardNanos = "/api/v0/admin/set-captcha-reward-nanos" // tutorial.go RoutePathGetTutorialCreators = "/api/v0/get-tutorial-creators" @@ -452,7 +454,8 @@ type APIServer struct { CountKeysWithDESO uint64 // map of country name to sign up bonus data - AllCountryLevelSignUpBonuses map[string]CountrySignUpBonusResponse + allCountryLevelSignUpBonusesLock sync.RWMutex + AllCountryLevelSignUpBonuses map[string]CountrySignUpBonusResponse // Frequently accessed data from global state USDCentsToDESOReserveExchangeRate uint64 @@ -1112,6 +1115,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.VerifyEmail, PublicAccess, }, + { + "VerifyCaptcha", + []string{"POST", "OPTIONS"}, + RoutePathVerifyCaptcha, + fes.HandleCaptchaVerificationRequest, + PublicAccess, + }, { "GetUserDerivedKeys", []string{"POST", "OPTIONS"}, @@ -1753,6 +1763,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.AdminResetPhoneNumber, SuperAdminAccess, }, + { + "SetCaptchaRewardNanos", + []string{"POST", "OPTIONS"}, + RoutePathAdminSetCaptchaRewardNanos, + fes.AdminSetCaptchaRewardNanos, + SuperAdminAccess, + }, // End all /admin routes // GET endpoints for managing parameters related to Buying DeSo { @@ -2607,11 +2624,20 @@ func (fes *APIServer) StartSeedBalancesMonitoring() { return } tags := []string{} - fes.logBalanceForSeed(fes.Config.StarterDESOSeed, "STARTER_DESO", tags) - fes.logBalanceForSeed(fes.Config.BuyDESOSeed, "BUY_DESO", tags) - for label, publicKey := range fes.Config.PublicKeyBalancesToMonitor { - fes.logBalanceForPublicKey(publicKey, label, tags) - } + // Use an inner function to unlock the mutex with a defer statement. + func() { + // If we're syncing a snapshot, we need to lock the DB in case the DB is restarted. This happens + // at the end of the snapshot sync. + if fes.backendServer.GetBlockchain().ChainState() == lib.SyncStateSyncingSnapshot { + fes.backendServer.DbMutex.Lock() + defer fes.backendServer.DbMutex.Unlock() + } + fes.logBalanceForSeed(fes.Config.StarterDESOSeed, "STARTER_DESO", tags) + fes.logBalanceForSeed(fes.Config.BuyDESOSeed, "BUY_DESO", tags) + for label, publicKey := range fes.Config.PublicKeyBalancesToMonitor { + fes.logBalanceForPublicKey(publicKey, label, tags) + } + }() case <-fes.quit: break out } @@ -2692,6 +2718,12 @@ func (fes *APIServer) SetGlobalStateCache() { if fes.backendServer == nil { return } + // If we're syncing a snapshot, we need to lock the DB in case the DB is restarted. This happens at + // the end of the snapshot sync. + if fes.backendServer.GetBlockchain().ChainState() == lib.SyncStateSyncingSnapshot { + fes.backendServer.DbMutex.Lock() + defer fes.backendServer.DbMutex.Unlock() + } utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() if err != nil { glog.Errorf("SetGlobalStateCache: problem with GetAugmentedUniversalView: %v", err) diff --git a/routes/supply.go b/routes/supply.go index 83743504..f6114dd4 100644 --- a/routes/supply.go +++ b/routes/supply.go @@ -44,6 +44,11 @@ func (fes *APIServer) StartSupplyMonitoring() { } func (fes *APIServer) UpdateSupplyStats() { + // Prevent access to the DB while it's reset. This only happens when we're syncing a snapshot. + if fes.backendServer.GetBlockchain().ChainState() == lib.SyncStateSyncingSnapshot { + fes.backendServer.DbMutex.Lock() + defer fes.backendServer.DbMutex.Unlock() + } totalSupply := uint64(0) totalKeysWithDESO := uint64(0) // Get all the balances from the DB diff --git a/routes/transaction.go b/routes/transaction.go index b3355b50..11667c73 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -25,7 +25,7 @@ import ( ) type GetTxnRequest struct { - // TxnHash to fetch. + // TxnHashHex to fetch. TxnHashHex string `safeForLogging:"true"` } @@ -459,14 +459,16 @@ func (fes *APIServer) CompProfileCreation(profilePublicKey []byte, userMetadata } // Additional fee is set to the create profile fee when we are creating a profile additionalFees := utxoView.GlobalParamsEntry.CreateProfileFeeNanos - + if additionalFees == 0 { + return 0, nil, nil + } existingMetamaskAirdropMetadata, err := fes.GetMetamaskAirdropMetadata(profilePublicKey) if err != nil { return 0, nil, fmt.Errorf("Error geting metamask airdrop metadata from global state: %v", err) } // Only comp create profile fee if frontend server has both twilio and starter deso seed configured and the user // has verified their profile. - if !fes.Config.CompProfileCreation || fes.Config.StarterDESOSeed == "" || fes.Twilio == nil || (userMetadata.PhoneNumber == "" && !userMetadata.JumioVerified && existingMetamaskAirdropMetadata == nil) { + if !fes.Config.CompProfileCreation || fes.Config.StarterDESOSeed == "" || (fes.Config.HCaptchaSecret == "" && fes.Twilio == nil) || (userMetadata.PhoneNumber == "" && !userMetadata.JumioVerified && existingMetamaskAirdropMetadata == nil && userMetadata.LastHcaptchaBlockHeight == 0) { return additionalFees, nil, nil } var currentBalanceNanos uint64 @@ -507,11 +509,16 @@ func (fes *APIServer) CompProfileCreation(profilePublicKey []byte, userMetadata return additionalFees, nil, nil } updateMetamaskAirdropMetadata = true - } else { + } else if userMetadata.JumioVerified { // User has been Jumio verified but should comp profile creation is false, just return if !userMetadata.JumioShouldCompProfileCreation { return additionalFees, nil, nil } + } else if userMetadata.LastHcaptchaBlockHeight != 0 { + // User has been captcha verified but should comp profile creation is false, just return + if !userMetadata.HcaptchaShouldCompProfileCreation { + return additionalFees, nil, nil + } } // Find the minimum starter bit deso amount @@ -530,6 +537,10 @@ func (fes *APIServer) CompProfileCreation(profilePublicKey []byte, userMetadata // We comp the create profile fee minus the minimum starter deso amount divided by 2. // This discourages botting while covering users who verify a phone number. compAmount := createProfileFeeNanos - (minStarterDESONanos / 2) + if (minStarterDESONanos / 2) > createProfileFeeNanos { + compAmount = createProfileFeeNanos + } + // If the user won't have enough deso to cover the fee, this is an error. if currentBalanceNanos+compAmount < createProfileFeeNanos { return 0, nil, fmt.Errorf("Creating a profile requires DeSo. Please purchase some to create a profile.") @@ -547,6 +558,11 @@ func (fes *APIServer) CompProfileCreation(profilePublicKey []byte, userMetadata if err = fes.putPhoneNumberMetadataInGlobalState(newPhoneNumberMetadata, userMetadata.PhoneNumber); err != nil { return 0, nil, fmt.Errorf("UpdateProfile: Error setting ShouldComp to false for phone number metadata: %v", err) } + } else if userMetadata.LastHcaptchaBlockHeight != 0 { + userMetadata.HcaptchaShouldCompProfileCreation = false + if err = fes.putUserMetadataInGlobalState(userMetadata); err != nil { + return 0, nil, fmt.Errorf("UpdateProfile: Error setting ShouldComp to false for jumio user metadata: %v", err) + } } else { // Set JumioShouldCompProfileCreation to false so we don't continue to comp profile creation. userMetadata.JumioShouldCompProfileCreation = false @@ -978,10 +994,11 @@ func (fes *APIServer) ExceedsDeSoBalance(nanosPurchased uint64, seed string) (bo // SendDeSoRequest ... type SendDeSoRequest struct { - SenderPublicKeyBase58Check string `safeForLogging:"true"` - RecipientPublicKeyOrUsername string `safeForLogging:"true"` - AmountNanos int64 `safeForLogging:"true"` - MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + SenderPublicKeyBase58Check string `safeForLogging:"true"` + RecipientPublicKeyOrUsername string `safeForLogging:"true"` + AmountNanos int64 `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` @@ -1059,6 +1076,12 @@ func (fes *APIServer) SendDeSo(ww http.ResponseWriter, req *http.Request) { return } + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("SendDeSo: Problem encoding ExtraData: %v", err)) + return + } + // If the AmountNanos is less than zero then we have a special case where we create // a transaction with the maximum spend. var txnn *lib.MsgDeSoTxn @@ -1069,8 +1092,8 @@ func (fes *APIServer) SendDeSo(ww http.ResponseWriter, req *http.Request) { if requestData.AmountNanos < 0 { // Create a MAX transaction txnn, totalInputt, spendAmountt, feeNanoss, err = fes.blockchain.CreateMaxSpend( - senderPkBytes, recipientPkBytes, requestData.MinFeeRateNanosPerKB, - fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) + senderPkBytes, recipientPkBytes, extraData, requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDeSo: Error processing MAX transaction: %v", err)) return @@ -1100,6 +1123,10 @@ func (fes *APIServer) SendDeSo(ww http.ResponseWriter, req *http.Request) { // inputs and change. } + if len(extraData) > 0 { + txnn.ExtraData = extraData + } + // Add inputs to the transaction and do signing, validation, and broadcast // depending on what the user requested. totalInputt, spendAmountt, changeAmountt, feeNanoss, err = @@ -2107,6 +2134,8 @@ type SendDiamondsRequest struct { MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` @@ -2182,6 +2211,12 @@ func (fes *APIServer) SendDiamonds(ww http.ResponseWriter, req *http.Request) { return } + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("SendDiamonds: Problem encoding extra data: %v", err)) + return + } + // Try and create the transfer with diamonds for the user. // We give diamonds in DESO if we're past the corresponding block height. blockHeight := fes.blockchain.BlockTip().Height + 1 @@ -2201,6 +2236,7 @@ func (fes *APIServer) SendDiamonds(ww http.ResponseWriter, req *http.Request) { senderPublicKeyBytes, diamondPostHash, requestData.DiamondLevel, + extraData, // Standard transaction fields requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) diff --git a/routes/verify.go b/routes/verify.go index 97237d85..e668b593 100644 --- a/routes/verify.go +++ b/routes/verify.go @@ -141,8 +141,9 @@ func (fes *APIServer) canUserCreateProfile(userMetadata *UserMetadata, utxoView return false, err } // User can create a profile if they have a phone number or if they have enough DeSo to cover the create profile fee. + // User can also create a profile if they've successfully filled out a captcha. // The PhoneNumber is only set if the user has passed phone number verification. - if userMetadata.PhoneNumber != "" || totalBalanceNanos >= utxoView.GlobalParamsEntry.CreateProfileFeeNanos { + if userMetadata.PhoneNumber != "" || totalBalanceNanos >= utxoView.GlobalParamsEntry.CreateProfileFeeNanos || userMetadata.LastHcaptchaBlockHeight > 0 { return true, nil } @@ -251,6 +252,213 @@ func (fes *APIServer) validatePhoneNumberNotAlreadyInUse(phoneNumber string, use return nil } +type SubmitCaptchaVerificationRequest struct { + Token string + JWT string + PublicKeyBase58Check string +} + +type SubmitCaptchaVerificationResponse struct { + Success bool + TxnHashHex string +} + +func (fes *APIServer) HandleCaptchaVerificationRequest(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := SubmitCaptchaVerificationRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("HandleCaptchaVerificationRequest: Problem parsing request body: %v", err)) + return + } + + // Validate their permissions + isValid, err := fes.ValidateJWT(requestData.PublicKeyBase58Check, requestData.JWT) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("HandleCaptchaVerificationRequest: Error validating JWT: %v", err)) + } + if !isValid { + _AddBadRequestError(ww, fmt.Sprintf("HandleCaptchaVerificationRequest: Invalid token: %v", err)) + return + } + + txnHashHex, err := fes.verifyHCaptchaTokenAndSendStarterDESO(requestData.Token, requestData.PublicKeyBase58Check) + + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("HandleCaptchaVerificationRequest: Error verifying captcha: %v", err)) + return + } + + res := SubmitCaptchaVerificationResponse{ + Success: true, + TxnHashHex: txnHashHex, + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("HandleCaptchaVerificationRequest: Problem encoding response: %v", err)) + return + } +} + +type AdminUpdateCaptchaRewardRequest struct { + // Amount of nanos to reward for a successful captcha. + RewardNanos uint64 +} + +type AdminUpdateCaptchaRewardResponse struct { + // Amount of nanos to reward for a successful captcha. + RewardNanos uint64 +} + +// HandleAdminUpdateCaptchaRewardRequest allows an admin to update the captcha reward amount. +func (fes *APIServer) AdminSetCaptchaRewardNanos(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := AdminUpdateCaptchaRewardRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("HandleAdminUpdateCaptchaRewardRequest: Problem parsing request body: %v", err)) + return + } + + // Ensure that the reward amount is not greater than the starter deso amount flag. + if requestData.RewardNanos > fes.Config.StarterDESONanos { + _AddBadRequestError(ww, fmt.Sprintf("HandleAdminUpdateCaptchaRewardRequest: Reward amount %v exceeds starter deso amount %v", requestData.RewardNanos, fes.Config.StarterDESONanos)) + return + } + + if err := fes.putCaptchaRewardNanosInGlobalState(requestData.RewardNanos); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("HandleAdminUpdateCaptchaRewardRequest: Error putting captcha reward in global state: %v", err)) + return + } + + res := AdminUpdateCaptchaRewardResponse{ + RewardNanos: requestData.RewardNanos, + } + if err := json.NewEncoder(ww).Encode(res); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("HandleAdminUpdateCaptchaRewardRequest: Problem encoding response: %v", err)) + return + } +} + +// getCaptchaRewardNanosFromGlobalState returns the amount of nanos to reward for a successful captcha from global state. +func (fes *APIServer) getCaptchaRewardNanosFromGlobalState() (uint64, error) { + dbKey := GlobalStateKeyForCaptchaRewardAmountNanos() + + rewardNanosBytes, err := fes.GlobalState.Get(dbKey) + if err != nil { + return 0, fmt.Errorf( + "getCaptchaRewardNanosFromGlobalState: Problem with Get: %v", err) + } + + rewardNanos, err := lib.ReadUvarint(bytes.NewReader(rewardNanosBytes)) + + return rewardNanos, nil +} + +// putCaptchaRewardNanosInGlobalState puts the amount of nanos to reward for a successful captcha in global state. +func (fes *APIServer) putCaptchaRewardNanosInGlobalState(rewardNanos uint64) error { + dbKey := GlobalStateKeyForCaptchaRewardAmountNanos() + + rewardNanosBytes := lib.UintToBuf(rewardNanos) + + if err := fes.GlobalState.Put(dbKey, rewardNanosBytes); err != nil { + return fmt.Errorf( + "putCaptchaRewardNanosInGlobalState: Problem with Put: %v", err) + } + + return nil +} + +// verifyHCaptchaTokenAndSendStarterDESO verifies the captcha token and sends the starter DESO to the user. +func (fes *APIServer) verifyHCaptchaTokenAndSendStarterDESO(token string, publicKeyBase58Check string) (txnHashHex string, err error) { + if fes.Config.StarterDESOSeed == "" { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: Starter DESO seed not set") + } + + // Retrieve the amount of nanos to reward for a successful captcha. + amountToSendNanos, err := fes.getCaptchaRewardNanosFromGlobalState() + if err != nil { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: Problem with getCaptchaRewardNanosFromGlobalState: %v", err) + } + + // Decode the public key. + publicKeyBytes, _, err := lib.Base58CheckDecode(publicKeyBase58Check) + if err != nil { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: Problem decoding public key: %v", err) + } + + // Ensure the user has not already received the starter DESO for submitting a successful captcha. + userMetadata, err := fes.getUserMetadataFromGlobalState(publicKeyBase58Check) + if err != nil { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: Problem with getUserMetadataFromGlobalState: %v", err) + } + + if userMetadata.LastHcaptchaBlockHeight != 0 { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: LastHcaptchaBlockHeight is already set") + } + + // Verify the token with hCaptcha. + verificationSuccess, err := fes.verifyHCaptchaToken(token) + + if err != nil { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: Error verifying captcha: %v", err) + } + + if !verificationSuccess { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: Captcha verification failed") + } + + // Update the user's metadata to indicate that they have received the starter DESO. + lastBlockheight := fes.blockchain.BlockTip().Height + userMetadata.LastHcaptchaBlockHeight = lastBlockheight + userMetadata.HcaptchaShouldCompProfileCreation = true + + if err = fes.putUserMetadataInGlobalState(userMetadata); err != nil { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: Problem with putUserMetadataInGlobalState: %v", err) + } + + // Send the starter DESO to the user. + var txnHash *lib.BlockHash + txnHash, err = fes.SendSeedDeSo(publicKeyBytes, amountToSendNanos, false) + if err != nil { + return "", fmt.Errorf("HandleCaptchaVerificationRequest: Error sending seed DeSo: %v", err) + } + + // Log the transaction to datadog. + if fes.backendServer.GetStatsdClient() != nil { + fes.backendServer.GetStatsdClient().Incr("SEND_STARTER_DESO_CAPTCHA", nil, 1) + } + + return txnHash.String(), nil +} + +type VerificationResponse struct { + Success bool `json:"success"` + ErrorCodes []string `json:"error-codes"` +} + +const VERIFY_URL = "https://hcaptcha.com/siteverify" + +// verifyHCaptchaToken verifies the captcha token via the hCaptcha API. +func (fes *APIServer) verifyHCaptchaToken(token string) (bool, error) { + // Construct and send the request to hcaptcha. + data := url.Values{} + data.Set("secret", fes.Config.HCaptchaSecret) + data.Set("response", token) + + resp, err := http.PostForm(VERIFY_URL, data) + if err != nil { + return false, err + } + defer resp.Body.Close() + + // Parse the response and return the result. + var verificationResponse VerificationResponse + err = json.NewDecoder(resp.Body).Decode(&verificationResponse) + if err != nil { + return false, err + } + + return verificationResponse.Success, nil +} + type SubmitPhoneNumberVerificationCodeRequest struct { JWT string PublicKeyBase58Check string diff --git a/scripts/nodes/n0 b/scripts/nodes/n0 index 84289258..a80aa764 100755 --- a/scripts/nodes/n0 +++ b/scripts/nodes/n0 @@ -18,6 +18,7 @@ rm /tmp/main.*.log --block-cypher-api-key=092dae962ea44b02809a4c74408b42a1 \ --min-satoshis-for-profile=0 \ --connect-ips=deso-seed-2.io:17000 \ + --hypersync-max-queue-size=10 \ --run-hot-feed-routine=true ) diff --git a/scripts/nodes/n0_test b/scripts/nodes/n0_test index fb9f8855..b12c2682 100755 --- a/scripts/nodes/n0_test +++ b/scripts/nodes/n0_test @@ -36,11 +36,12 @@ rm /tmp/main.*.log --block-producer-seed='essence camp ghost remove document vault ladder swim pupil index apart ring' \ --starter-deso-seed='road congress client market couple bid risk escape artwork rookie artwork food' \ --data-dir=/tmp/n0_test_00000 \ - --access-control-allow-origins=http://localhost:4200,http://localhost:80,http://localhost:18002,http://localhost:4201,http://localhost:18001 \ + --access-control-allow-origins=http://localhost:4200,http://localhost:80,http://localhost:18002,http://localhost:4201,http://localhost:18001,http://localhost:3000,localhost:3000 \ --secure-header-allow-hosts=localhost:4200 \ --secure-header-development=true \ --block-cypher-api-key=092dae962ea44b02809a4c74408b42a1 \ --min-satoshis-for-profile=0 \ --expose-global-state=true \ --show-processing-spinners=true \ + --comp-profile-creation=true \ --metamask-airdrop-deso-nanos-amount=1000 ) diff --git a/scripts/tools/clear_ancestral_records.go b/scripts/tools/clear_ancestral_records.go index cf7a9edb..7f862488 100644 --- a/scripts/tools/clear_ancestral_records.go +++ b/scripts/tools/clear_ancestral_records.go @@ -16,7 +16,7 @@ func main() { fmt.Printf("Error reading db1 err: %v", err) return } - snap, err, _ := lib.NewSnapshot(db, dbDir, lib.SnapshotBlockHeightPeriod, false, false, &lib.DeSoMainnetParams, false) + snap, err, _ := lib.NewSnapshot(db, dbDir, lib.SnapshotBlockHeightPeriod, false, false, &lib.DeSoMainnetParams, false, lib.HypersyncDefaultMaxQueueSize) if err != nil { fmt.Printf("Error reading snap err: %v", err) return diff --git a/test.Dockerfile b/test.Dockerfile index a1ed5cd2..a7970f17 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -7,6 +7,9 @@ RUN apk add --update bash cmake g++ gcc git make vips-dev COPY --from=golang:1.20-alpine /usr/local/go/ /usr/local/go/ ENV PATH="/usr/local/go/bin:${PATH}" +# Declare an ARG for the branch name with a default value of "main" +ARG BRANCH_NAME=main + WORKDIR /deso/src RUN git clone https://github.com/deso-protocol/core.git @@ -19,6 +22,9 @@ RUN git pull && \ RUN go mod download RUN ./scripts/install-relic.sh +# Try to checkout to the specified branch. If it fails, checkout main. +RUN git checkout ${BRANCH_NAME} || (echo "Branch ${BRANCH_NAME} not found. Falling back to main." && git checkout main) + WORKDIR /deso/src/backend COPY go.mod . From e392f7f008943d5416df75c1e1ea8fb2e99577c9 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:31:55 -0500 Subject: [PATCH 17/84] Remove fee estimator from txn construction calls (#520) Co-authored-by: Lazy Nina <> --- routes/access_group.go | 6 ++---- routes/admin_transaction.go | 4 ++-- routes/associations.go | 4 ---- routes/exchange.go | 15 +++++++------- routes/message.go | 6 ++---- routes/new_message.go | 2 +- routes/nft.go | 21 +++++++------------ routes/server.go | 2 +- routes/shared.go | 3 +-- routes/transaction.go | 41 +++++++++++++------------------------ routes/user.go | 6 +++--- routes/validators.go | 2 -- 12 files changed, 41 insertions(+), 71 deletions(-) diff --git a/routes/access_group.go b/routes/access_group.go index 873f3d01..6a5b7278 100644 --- a/routes/access_group.go +++ b/routes/access_group.go @@ -117,8 +117,7 @@ func (fes *APIServer) accessGroupHandler( accessGroupOwnerPkBytes, accessGroupPkBytes, accessGroupKeyNameBytes, accessGroupOperationType, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { return fmt.Errorf("problem creating transaction: %v", err) } @@ -398,8 +397,7 @@ func (fes *APIServer) accessGroupMemberHandler( accessGroupOwnerPkBytes, accessGroupKeyNameBytes, accessGroupMembers, accessGroupMemberOperationType, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { return fmt.Errorf("problem creating transaction: %v", err) } diff --git a/routes/admin_transaction.go b/routes/admin_transaction.go index 7b2f5277..4f6bbceb 100644 --- a/routes/admin_transaction.go +++ b/routes/admin_transaction.go @@ -273,7 +273,7 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque maxNonceExpirationBlockHeightOffset, extraData, requestData.MinFeeRateNanosPerKB, - fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) + fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateGlobalParams: Problem creating transaction: %v", err)) return @@ -401,7 +401,7 @@ func (fes *APIServer) SwapIdentity(ww http.ResponseWriter, req *http.Request) { toPublicKey, requestData.MinFeeRateNanosPerKB, - fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) + fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SwapIdentity: Problem creating transaction: %v", err)) return diff --git a/routes/associations.go b/routes/associations.go index 23f88b5e..14c9f9b7 100644 --- a/routes/associations.go +++ b/routes/associations.go @@ -252,7 +252,6 @@ func (fes *APIServer) CreateUserAssociation(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("CreateUserAssociation: problem creating txn: %v", err)) @@ -338,7 +337,6 @@ func (fes *APIServer) DeleteUserAssociation(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("DeleteUserAssociation: problem creating txn: %v", err)) @@ -806,7 +804,6 @@ func (fes *APIServer) CreatePostAssociation(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("CreatePostAssociation: problem creating txn: %v", err)) @@ -892,7 +889,6 @@ func (fes *APIServer) DeletePostAssociation(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("DeletePostAssociation: problem creating txn: %v", err)) diff --git a/routes/exchange.go b/routes/exchange.go index a65cdb88..a75cade4 100644 --- a/routes/exchange.go +++ b/routes/exchange.go @@ -378,7 +378,7 @@ func (fes *APIServer) APIBalance(ww http.ResponseWriter, rr *http.Request) { } // Get all the UTXOs for the public key. - utxoView, err := fes.mempool.GetAugmentedUtxoViewForPublicKey(publicKeyBytes, nil) + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUtxoViewForPublicKey(publicKeyBytes, nil) if err != nil { APIAddError(ww, fmt.Sprintf("APIBalanceRequest: Problem getting UTXOs for public key: %v", err)) return @@ -776,8 +776,7 @@ func (fes *APIServer) APITransferDeSo(ww http.ResponseWriter, rr *http.Request) // Create a MAX transaction txnn, totalInputt, spendAmountt, feeNanoss, err = fes.blockchain.CreateMaxSpend( senderPublicKeyBytes, recipientPub.SerializeCompressed(), nil, - uint64(minFeeRateNanosPerKB), - fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) + uint64(minFeeRateNanosPerKB), fes.backendServer.GetMempool(), additionalOutputs) if err != nil { APIAddError(ww, fmt.Sprintf("APITransferDeSo: Error processing MAX transaction: %v", err)) return @@ -980,7 +979,7 @@ func (fes *APIServer) APITransactionInfo(ww http.ResponseWriter, rr *http.Reques // IsMempool means we should just return all of the transactions that are currently in the mempool. if transactionInfoRequest.IsMempool { // Get all the txns from the mempool. - poolTxns := fes.mempool.GetOrderedTransactions() + poolTxns := fes.backendServer.GetMempool().GetOrderedTransactions() res := &APITransactionInfoResponse{} res.Transactions = []*TransactionResponse{} @@ -1047,7 +1046,7 @@ func (fes *APIServer) APITransactionInfo(ww http.ResponseWriter, rr *http.Reques if txn == nil { // Try to look the transaction up in the mempool before giving up. - txnInPool := fes.mempool.GetMempoolTx(txID) + txnInPool := fes.backendServer.GetMempool().GetMempoolTx(txID) if txnInPool == nil { APIAddError(ww, fmt.Sprintf("APITransactionInfo: Could not find transaction with TransactionIDBase58Check = %s", transactionInfoRequest.TransactionIDBase58Check)) @@ -1162,7 +1161,7 @@ func (fes *APIServer) APITransactionInfo(ww http.ResponseWriter, rr *http.Reques if transactionInfoRequest.LastPublicKeyTransactionIndex <= 0 { // Start with the mempool - poolTxns := fes.mempool.GetOrderedTransactions() + poolTxns := fes.backendServer.GetMempool().GetOrderedTransactions() // Go from most recent to least recent // TODO: Support pagination for mempool transactions @@ -1416,6 +1415,8 @@ func (fes *APIServer) _processTransactionWithKey( // transaction will be mined at the earliest. blockHeight+1, true, + // TODO: Do we want to use fes.backendServer.GetMempool here? + // There are probably other updates we need to make here for PoS as well. fes.mempool) if err != nil { return fmt.Errorf("_processTransactionWithKey: Problem validating txn: %v", err) @@ -1449,7 +1450,7 @@ func (fes *APIServer) _augmentAndProcessTransactionWithSubsidyWithKey( // return an error. totalInput, spendAmount, changeAmount, fees, err := fes.blockchain.AddInputsAndChangeToTransactionWithSubsidy(txn, minFeeRateNanosPerKB, - inputSubsidy, fes.mempool, 0, fes.backendServer.GetFeeEstimator()) + inputSubsidy, fes.backendServer.GetMempool(), 0) if err != nil { return 0, 0, 0, 0, fmt.Errorf("_augmentAndProcessTransactionWithKey: Problem adding inputs and "+ "change to transaction %v: %v", txn, err) diff --git a/routes/message.go b/routes/message.go index 8f150d4b..e30f75a8 100644 --- a/routes/message.go +++ b/routes/message.go @@ -714,8 +714,7 @@ func (fes *APIServer) SendMessageStateless(ww http.ResponseWriter, req *http.Req senderMessagingPublicKey, senderMessagingGroupKeyNameBytes, recipientMessagingPublicKey, recipientMessagingGroupKeyNameBytes, tstamp, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendMessageStateless: Problem creating transaction: %v", err)) return @@ -974,8 +973,7 @@ func (fes *APIServer) RegisterMessagingGroupKey(ww http.ResponseWriter, req *htt txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateMessagingKeyTxn( ownerPkBytes, messagingPkBytes, messagingKeyNameBytes, messagingKeySignature, []*lib.MessagingGroupMember{}, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("RegisterMessagingGroupKey: Problem creating transaction: %v", err)) return diff --git a/routes/new_message.go b/routes/new_message.go index c428c382..67ed7f27 100644 --- a/routes/new_message.go +++ b/routes/new_message.go @@ -377,7 +377,7 @@ func (fes *APIServer) sendMessageHandler( *lib.NewPublicKey(recipientGroupOwnerPkBytes), *lib.NewGroupKeyName(recipientGroupKeyNameBytes), *lib.NewPublicKey(recipientAccessGroupPkbytes), hexDecodedEncryptedMessageBytes, tstamp, newMessageType, newMessageOperationType, extraData, requestData.MinFeeRateNanosPerKB, - fes.backendServer.GetMempool(), additionalOutputs, fes.backendServer.GetFeeEstimator()) + fes.backendServer.GetMempool(), additionalOutputs) if err != nil { return errors.Wrapf(err, "Problem creating transaction: ") } diff --git a/routes/nft.go b/routes/nft.go index d730d16b..c6affae5 100644 --- a/routes/nft.go +++ b/routes/nft.go @@ -262,8 +262,7 @@ func (fes *APIServer) CreateNFT(ww http.ResponseWriter, req *http.Request) { additionalDESORoyaltiesPubKeyMap, additionalCoinRoyaltiesPubKeyMap, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateNFT: Problem creating transaction: %v", err)) return @@ -412,8 +411,7 @@ func (fes *APIServer) UpdateNFT(ww http.ResponseWriter, req *http.Request) { uint64(requestData.MinBidAmountNanos), requestData.IsBuyNow, requestData.BuyNowPriceNanos, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateNFT: Problem creating transaction: %v", err)) return @@ -570,8 +568,7 @@ func (fes *APIServer) CreateNFTBid(ww http.ResponseWriter, req *http.Request) { nftPostHash, uint64(requestData.SerialNumber), uint64(requestData.BidAmountNanos), - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateNFTBid: Problem creating transaction: %v", err)) return @@ -734,8 +731,7 @@ func (fes *APIServer) AcceptNFTBid(ww http.ResponseWriter, req *http.Request) { bidderPKID.PKID, uint64(requestData.BidAmountNanos), encryptedUnlockableTextBytes, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AcceptNFTBid: Problem creating transaction: %v", err)) return @@ -1653,8 +1649,7 @@ func (fes *APIServer) TransferNFT(ww http.ResponseWriter, req *http.Request) { nftPostHash, uint64(requestData.SerialNumber), []byte(requestData.EncryptedUnlockableText), - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferNFT: Problem creating transaction: %v", err)) return @@ -1794,8 +1789,7 @@ func (fes *APIServer) AcceptNFTTransfer(ww http.ResponseWriter, req *http.Reques updaterPublicKeyBytes, nftPostHash, uint64(requestData.SerialNumber), - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AcceptNFTTransfer: Problem creating transaction: %v", err)) return @@ -1934,8 +1928,7 @@ func (fes *APIServer) BurnNFT(ww http.ResponseWriter, req *http.Request) { updaterPublicKeyBytes, nftPostHash, uint64(requestData.SerialNumber), - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("BurnNFT: Problem creating transaction: %v", err)) return diff --git a/routes/server.go b/routes/server.go index 710a0d4c..9d5f0877 100644 --- a/routes/server.go +++ b/routes/server.go @@ -2490,7 +2490,7 @@ func (fes *APIServer) ValidateJWT(publicKey string, jwtToken string) (bool, erro return nil, errors.Wrapf(err, "Problem parsing derived public key bytes") } // Validate the derived public key. - utxoView, err := fes.mempool.GetAugmentedUniversalView() + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() if err != nil { return nil, errors.Wrapf(err, "Problem getting utxoView") } diff --git a/routes/shared.go b/routes/shared.go index 2a82de51..d5a67200 100644 --- a/routes/shared.go +++ b/routes/shared.go @@ -397,8 +397,7 @@ func (fes *APIServer) SendSeedDeSo(recipientPkBytes []byte, amountNanos uint64, if utxoView.GlobalParamsEntry != nil && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB > 0 { minFee = utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB } - _, _, _, _, err = fes.blockchain.AddInputsAndChangeToTransaction(txn, minFee, fes.mempool, - fes.backendServer.GetFeeEstimator()) + _, _, _, _, err = fes.blockchain.AddInputsAndChangeToTransaction(txn, minFee, fes.backendServer.GetMempool()) if err != nil { return nil, fmt.Errorf("SendSeedDeSo: Error adding inputs for seed DeSo: %v", err) } diff --git a/routes/transaction.go b/routes/transaction.go index 11667c73..d1eea6ec 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -57,7 +57,7 @@ func (fes *APIServer) GetTxn(ww http.ResponseWriter, req *http.Request) { copy(txnHash[:], txnHashBytes) } - txnFound := fes.mempool.IsTransactionInPool(txnHash) + txnFound := fes.backendServer.GetMempool().IsTransactionInPool(txnHash) if !txnFound { txnFound = lib.DbCheckTxnExistence(fes.TXIndex.TXIndexChain.DB(), nil, txnHash) } @@ -409,8 +409,7 @@ func (fes *APIServer) UpdateProfile(ww http.ResponseWriter, req *http.Request) { requestData.IsHidden, additionalFees, extraData, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Problem creating transaction: %v", err)) return @@ -1131,8 +1130,7 @@ func (fes *APIServer) SendDeSo(ww http.ResponseWriter, req *http.Request) { // depending on what the user requested. totalInputt, spendAmountt, changeAmountt, feeNanoss, err = fes.blockchain.AddInputsAndChangeToTransaction( - txnn, requestData.MinFeeRateNanosPerKB, fes.mempool, - fes.backendServer.GetFeeEstimator()) + txnn, requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDeSo: Error processing transaction: %v", err)) return @@ -1241,8 +1239,7 @@ func (fes *APIServer) CreateLikeStateless(ww http.ResponseWriter, req *http.Requ // Try and create the message for the user. txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateLikeTxn( readerPkBytes, postHash, requestData.IsUnlike, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateLikeStateless: Problem creating transaction: %v", err)) return @@ -1492,8 +1489,7 @@ func (fes *APIServer) SubmitPost(ww http.ResponseWriter, req *http.Request) { tstamp, postExtraData, requestData.IsHidden, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SubmitPost: Problem creating transaction: %v", err)) return @@ -1646,8 +1642,7 @@ func (fes *APIServer) CreateFollowTxnStateless(ww http.ResponseWriter, req *http // Try and create the follow for the user. txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateFollowTxn( followerPkBytes, followedPkBytes, requestData.IsUnfollow, - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateFollowTxnStateless: Problem creating transaction: %v", err)) return @@ -1821,8 +1816,7 @@ func (fes *APIServer) BuyOrSellCreatorCoin(ww http.ResponseWriter, req *http.Req requestData.MinDeSoExpectedNanos, requestData.MinCreatorCoinExpectedNanos, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("BuyOrSellCreatorCoin: Problem adding inputs and change transaction: %v", err)) return @@ -1831,7 +1825,7 @@ func (fes *APIServer) BuyOrSellCreatorCoin(ww http.ResponseWriter, req *http.Req // Add node source to txn metadata fes.AddNodeSourceToTxnMetadata(txn) - utxoView, err := fes.mempool.GetAugmentedUtxoViewForPublicKey(updaterPublicKeyBytes, txn) + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUtxoViewForPublicKey(updaterPublicKeyBytes, txn) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("BuyOrSellCreatorCoin: Problem computing view for transaction: %v", err)) return @@ -2086,8 +2080,7 @@ func (fes *APIServer) TransferCreatorCoin(ww http.ResponseWriter, req *http.Requ requestData.CreatorCoinToTransferNanos, receiverPublicKeyBytes, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferCreatorCoin: Problem creating transaction: %v", err)) return @@ -2238,8 +2231,7 @@ func (fes *APIServer) SendDiamonds(ww http.ResponseWriter, req *http.Request) { requestData.DiamondLevel, extraData, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDiamonds: Problem creating transaction: %v", err)) return @@ -2258,8 +2250,7 @@ func (fes *APIServer) SendDiamonds(ww http.ResponseWriter, req *http.Request) { diamondPostHash, requestData.DiamondLevel, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDiamonds: Problem creating transaction: %v", err)) return @@ -2481,8 +2472,7 @@ func (fes *APIServer) DAOCoin(ww http.ResponseWriter, req *http.Request) { TransferRestrictionStatus: transferRestrictionStatus, }, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("DAOCoin: Problem adding inputs and change transaction: %v", err)) return @@ -2617,8 +2607,7 @@ func (fes *APIServer) TransferDAOCoin(ww http.ResponseWriter, req *http.Request) DAOCoinToTransferNanos: requestData.DAOCoinToTransferNanos, }, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferDAOCoin: Problem creating transaction: %v", err)) return @@ -3173,7 +3162,6 @@ func (fes *APIServer) createDAOCoinLimitOrderResponse( minFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator(), ) if err != nil { @@ -3420,8 +3408,7 @@ func (fes *APIServer) AuthorizeDerivedKey(ww http.ResponseWriter, req *http.Requ memo, requestData.TransactionSpendingLimitHex, // Standard transaction fields - requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator()) + requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AuthorizeDerivedKey: Problem creating transaction: %v", err)) return diff --git a/routes/user.go b/routes/user.go index a38ec364..62a2e24d 100644 --- a/routes/user.go +++ b/routes/user.go @@ -2535,7 +2535,7 @@ func (fes *APIServer) _getMempoolNotifications(request *GetNotificationsRequest, // // TODO(performance): This could get slow if the mempool gets big. Fix is to organize everything // in the mempool by public key and only look up transactions that are relevant to this public key. - poolTxns := fes.mempool.GetOrderedTransactions() + poolTxns := fes.backendServer.GetMempool().GetOrderedTransactions() mempoolTxnMetadata := []*TransactionMetadataResponse{} for _, poolTx := range poolTxns { @@ -2631,7 +2631,7 @@ func (fes *APIServer) _getNotificationsCount(request *GetNotificationsRequest) ( // A valid mempool object is used to compute the TransactionMetadata for the mempool // and to allow for things like: filtering notifications for a hidden post. - utxoView, err := fes.mempool.GetAugmentedUniversalView() + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() if err != nil { return 0, 0, errors.Errorf("GetNotifications: Problem getting view: %v", err) } @@ -2685,7 +2685,7 @@ func (fes *APIServer) _getNotifications(request *GetNotificationsRequest) ([]*Tr // A valid mempool object is used to compute the TransactionMetadata for the mempool // and to allow for things like: filtering notifications for a hidden post. - utxoView, err := fes.mempool.GetAugmentedUniversalView() + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() if err != nil { return nil, nil, errors.Errorf("GetNotifications: Problem getting view: %v", err) } diff --git a/routes/validators.go b/routes/validators.go index 5ac46603..687a668d 100644 --- a/routes/validators.go +++ b/routes/validators.go @@ -125,7 +125,6 @@ func (fes *APIServer) RegisterAsValidator(ww http.ResponseWriter, req *http.Requ requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("RegisterAsValidator: problem creating txn: %v", err)) @@ -200,7 +199,6 @@ func (fes *APIServer) UnregisterAsValidator(ww http.ResponseWriter, req *http.Re requestData.MinFeeRateNanosPerKB, fes.backendServer.GetMempool(), additionalOutputs, - fes.backendServer.GetFeeEstimator(), ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("UnregisterAsValidator: problem creating txn: %v", err)) From c70fa5c9a58dfcb0755ed88b5b70797ca7829de2 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 5 Jan 2024 17:11:57 -0500 Subject: [PATCH 18/84] Fix compilation errors (#521) Co-authored-by: Lazy Nina <> --- routes/exchange_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/routes/exchange_test.go b/routes/exchange_test.go index c14592cd..d5c71937 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "encoding/json" + chainlib "github.com/btcsuite/btcd/blockchain" "github.com/deso-protocol/backend/config" coreCmd "github.com/deso-protocol/core/cmd" "github.com/deso-protocol/core/lib" @@ -13,6 +14,7 @@ import ( "net/http/httptest" "os" "testing" + "time" "github.com/dgraph-io/badger/v3" @@ -98,7 +100,7 @@ func NewLowDifficultyBlockchainWithParams(t *testing.T, params *lib.DeSoParams) Version: 0, PrevBlockHash: lib.MustDecodeHexBlockHash("0000000000000000000000000000000000000000000000000000000000000000"), TransactionMerkleRoot: lib.MustDecodeHexBlockHash("097158f0d27e6d10565c4dc696c784652c3380e0ff8382d3599a4d18b782e965"), - TstampSecs: uint64(1560735050), + TstampNanoSecs: uint64(1560735050), Height: uint64(0), Nonce: uint64(0), // No ExtraNonce is set in the genesis block @@ -172,7 +174,7 @@ func NewTestMiner(t *testing.T, chain *lib.Blockchain, params *lib.DeSoParams, i return mempool, newMiner } -func newTestAPIServer(t *testing.T, globalStateRemoteNode string) (*APIServer, *APIServer, *lib.DeSoMiner) { +func newTestAPIServer(t *testing.T, globalStateRemoteNode string, txindex bool) (*APIServer, *APIServer, *lib.DeSoMiner) { assert := assert.New(t) require := require.New(t) _, _ = assert, require From 753f14d16208c7a9ef0ad0e972994ae5b6b144a3 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 5 Jan 2024 17:37:01 -0500 Subject: [PATCH 19/84] Fix validator test (#522) Co-authored-by: Lazy Nina <> --- routes/validators_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/validators_test.go b/routes/validators_test.go index be7188b8..151b2f36 100644 --- a/routes/validators_test.go +++ b/routes/validators_test.go @@ -99,7 +99,7 @@ func TestValidatorRegistration(t *testing.T) { require.Equal(t, validatorResponse.VotingAuthorization, votingAuthorization.ToString()) require.Equal(t, validatorResponse.TotalStakeAmountNanos.Uint64(), uint64(0)) require.Equal(t, validatorResponse.Status, "Active") - require.Equal(t, validatorResponse.LastActiveAtEpochNumber, uint64(0)) + require.Equal(t, validatorResponse.LastActiveAtEpochNumber, uint64(1)) require.Equal(t, validatorResponse.JailedAtEpochNumber, uint64(0)) require.NotNil(t, validatorResponse.ExtraData) require.Equal(t, validatorResponse.ExtraData["Foo"], "Bar") From 43493e3388efbe5f2266d9e95668ef2fee18458f Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 5 Jan 2024 17:59:26 -0500 Subject: [PATCH 20/84] Add DelegatedStakeCommissionBasisPoints to RegisterAsValidator txn construction endpoint (#523) Co-authored-by: Lazy Nina <> --- routes/validators.go | 68 +++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/routes/validators.go b/routes/validators.go index 687a668d..c86e0afb 100644 --- a/routes/validators.go +++ b/routes/validators.go @@ -13,14 +13,15 @@ import ( ) type RegisterAsValidatorRequest struct { - TransactorPublicKeyBase58Check string `safeForLogging:"true"` - Domains []string `safeForLogging:"true"` - DisableDelegatedStake bool `safeForLogging:"true"` - VotingPublicKey string `safeForLogging:"true"` - VotingAuthorization string `safeForLogging:"true"` - ExtraData map[string]string `safeForLogging:"true"` - MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` - TransactionFees []TransactionFee `safeForLogging:"true"` + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + Domains []string `safeForLogging:"true"` + DisableDelegatedStake bool `safeForLogging:"true"` + DelegatedStakeCommissionBasisPoints uint64 `safeForLogging:"true"` + VotingPublicKey string `safeForLogging:"true"` + VotingAuthorization string `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` } type UnregisterAsValidatorRequest struct { @@ -41,16 +42,17 @@ type ValidatorTxnResponse struct { } type ValidatorResponse struct { - ValidatorPublicKeyBase58Check string - Domains []string - DisableDelegatedStake bool - VotingPublicKey string - VotingAuthorization string - TotalStakeAmountNanos *uint256.Int - Status string - LastActiveAtEpochNumber uint64 - JailedAtEpochNumber uint64 - ExtraData map[string]string + ValidatorPublicKeyBase58Check string + Domains []string + DisableDelegatedStake bool + DelegatedStakeCommissionBasisPoints uint64 + VotingPublicKey string + VotingAuthorization string + TotalStakeAmountNanos *uint256.Int + Status string + LastActiveAtEpochNumber uint64 + JailedAtEpochNumber uint64 + ExtraData map[string]string } func (fes *APIServer) RegisterAsValidator(ww http.ResponseWriter, req *http.Request) { @@ -116,10 +118,11 @@ func (fes *APIServer) RegisterAsValidator(ww http.ResponseWriter, req *http.Requ txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateRegisterAsValidatorTxn( transactorPublicKeyBytes, &lib.RegisterAsValidatorMetadata{ - Domains: domains, - DisableDelegatedStake: requestData.DisableDelegatedStake, - VotingPublicKey: votingPublicKey, - VotingAuthorization: votingAuthorization, + Domains: domains, + DisableDelegatedStake: requestData.DisableDelegatedStake, + DelegatedStakeCommissionBasisPoints: requestData.DelegatedStakeCommissionBasisPoints, + VotingPublicKey: votingPublicKey, + VotingAuthorization: votingAuthorization, }, extraData, requestData.MinFeeRateNanosPerKB, @@ -289,15 +292,16 @@ func _convertValidatorEntryToResponse( // Convert ValidatorEntry to ValidatorResponse. return &ValidatorResponse{ - ValidatorPublicKeyBase58Check: validatorPublicKeyBase58Check, - Domains: domains, - DisableDelegatedStake: validatorEntry.DisableDelegatedStake, - VotingPublicKey: validatorEntry.VotingPublicKey.ToString(), - VotingAuthorization: validatorEntry.VotingAuthorization.ToString(), - TotalStakeAmountNanos: validatorEntry.TotalStakeAmountNanos.Clone(), - Status: validatorEntry.Status().ToString(), - LastActiveAtEpochNumber: validatorEntry.LastActiveAtEpochNumber, - JailedAtEpochNumber: validatorEntry.JailedAtEpochNumber, - ExtraData: DecodeExtraDataMap(params, utxoView, validatorEntry.ExtraData), + ValidatorPublicKeyBase58Check: validatorPublicKeyBase58Check, + Domains: domains, + DisableDelegatedStake: validatorEntry.DisableDelegatedStake, + DelegatedStakeCommissionBasisPoints: validatorEntry.DelegatedStakeCommissionBasisPoints, + VotingPublicKey: validatorEntry.VotingPublicKey.ToString(), + VotingAuthorization: validatorEntry.VotingAuthorization.ToString(), + TotalStakeAmountNanos: validatorEntry.TotalStakeAmountNanos.Clone(), + Status: validatorEntry.Status().ToString(), + LastActiveAtEpochNumber: validatorEntry.LastActiveAtEpochNumber, + JailedAtEpochNumber: validatorEntry.JailedAtEpochNumber, + ExtraData: DecodeExtraDataMap(params, utxoView, validatorEntry.ExtraData), } } From c5f420c77bc6a2300b5d20d4afdabfc987c5440f Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 23 Jan 2024 14:42:45 -0500 Subject: [PATCH 21/84] Add stake, unstake, and unlock stake txn construction endpoints (#524) * Add stake, unstake, and unlock stake txn construction endpoints * Add stake, unstake, and unlock stake txn construction endpoints --------- Co-authored-by: Lazy Nina <> --- .gitignore | 1 + routes/server.go | 26 +++ routes/stake.go | 417 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 routes/stake.go diff --git a/.gitignore b/.gitignore index ca6db9b9..5851a585 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ local_scripts/* backend .idea +mem.log \ No newline at end of file diff --git a/routes/server.go b/routes/server.go index 9d5f0877..8cf6cb16 100644 --- a/routes/server.go +++ b/routes/server.go @@ -316,6 +316,11 @@ const ( // validators.go RoutePathValidators = "/api/v0/validators" + + // stake.go + RoutePathStake = "/api/v0/stake" + RoutePathUnstake = "/api/v0/unstake" + RoutePathUnlockStake = "/api/v0/unlock-stake" ) // APIServer provides the interface between the blockchain and things like the @@ -1304,6 +1309,27 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.GetValidatorByPublicKeyBase58Check, PublicAccess, }, + { + "CreateStakeTxn", + []string{"POST", "OPTIONS"}, + RoutePathStake, + fes.CreateStakeTxn, + PublicAccess, + }, + { + "CreateUnstakeTxn", + []string{"POST", "OPTIONS"}, + RoutePathUnstake, + fes.CreateUnstakeTxn, + PublicAccess, + }, + { + "CreateUnlockStakeTxn", + []string{"POST", "OPTIONS"}, + RoutePathUnlockStake, + fes.CreateUnlockStakeTxn, + PublicAccess, + }, // Jumio Routes { "JumioBegin", diff --git a/routes/stake.go b/routes/stake.go new file mode 100644 index 00000000..8b1d3aa9 --- /dev/null +++ b/routes/stake.go @@ -0,0 +1,417 @@ +package routes + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "github.com/deso-protocol/core/lib" + "github.com/holiman/uint256" + "io" + "net/http" +) + +type StakeRewardMethod string + +const ( + PayToBalance StakeRewardMethod = "PAY_TO_BALANCE" + Restake StakeRewardMethod = "RESTAKE" +) + +type StakeRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + ValidatorPublicKeyBase58Check string `safeForLogging:"true"` + RewardMethod StakeRewardMethod `safeForLogging:"true"` + StakeAmountNanos *uint256.Int `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type UnstakeRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + ValidatorPublicKeyBase58Check string `safeForLogging:"true"` + UnstakeAmountNanos *uint256.Int `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type UnlockStakeRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + ValidatorPublicKeyBase58Check string `safeForLogging:"true"` + StartEpochNumber uint64 `safeForLogging:"true"` + EndEpochNumber uint64 `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type StakeTxnResponse struct { + SpendAmountNanos uint64 + TotalInputNanos uint64 + ChangeAmountNanos uint64 + FeeNanos uint64 + Transaction *lib.MsgDeSoTxn + TransactionHex string + TxnHashHex string +} + +type StakeEntryResponse struct { + StakerPublicKeyBase58Check string + ValidatorPublicKeyBase58Check string + RewardMethod StakeRewardMethod + StakeAmountNanos *uint256.Int + ExtraData map[string]string +} + +type LockedStakeEntryResponse struct { + StakerPublicKeyBase58Check string + ValidatorPublicKeyBase58Check string + LockedAmountNanos *uint256.Int + LockedAtEpochNumber uint64 + ExtraData map[string]string +} + +func (fes *APIServer) CreateStakeTxn(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := StakeRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Problem parsing request body: %v", err)) + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CreateStakeTxn: TransactorPublicKeyBase58Check is required")) + return + } + transactorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Problem decoding TransactorPublicKeyBase58Check %s: %v", + requestData.TransactorPublicKeyBase58Check, err)) + return + } + + // Convert ValidatorPublicKeyBase58Check to ValidatorPublicKeyBytes + if requestData.ValidatorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CreateStakeTxn: ValidatorPublicKeyBase58Check is required")) + return + } + validatorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.ValidatorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Problem decoding ValidatorPublicKeyBase58Check %s: %v", + requestData.ValidatorPublicKeyBase58Check, err)) + return + } + + // Convert reward method string to enum. + var rewardMethod lib.StakingRewardMethod + switch requestData.RewardMethod { + case PayToBalance: + rewardMethod = lib.StakingRewardMethodPayToBalance + break + case Restake: + rewardMethod = lib.StakingRewardMethodRestake + break + default: + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Invalid RewardMethod %s", requestData.RewardMethod)) + return + } + + // Validate stake amount + if !requestData.StakeAmountNanos.IsUint64() { + _AddBadRequestError(ww, fmt.Sprint("CreateStakeTxn: StakeAmountNanos must be a uint64")) + return + } + stakeAmountNanosUint64 := requestData.StakeAmountNanos.Uint64() + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Problem fetching utxoView: %v", err)) + return + } + balance, err := utxoView.GetDeSoBalanceNanosForPublicKey(transactorPublicKeyBytes) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Problem fetching balance: %v", err)) + return + } + if stakeAmountNanosUint64 > balance { + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Insufficient balance: %d", balance)) + return + } + + // Parse ExtraData. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Problem parsing ExtraData: %v", err)) + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeStake, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprint("CreateStakeTxn: specified TransactionFees are invalid")) + return + } + + // Create transaction. + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateStakeTxn( + transactorPublicKeyBytes, + &lib.StakeMetadata{ + ValidatorPublicKey: lib.NewPublicKey(validatorPublicKeyBytes), + RewardMethod: rewardMethod, + StakeAmountNanos: requestData.StakeAmountNanos, + }, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Problem creating transaction: %v", err)) + return + } + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CreateStakeTxn: Problem serializing transaction: %v", err)) + return + } + + // TODO: do we need to specify the stake amount in the spend amount nanos? + res := StakeTxnResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, "CreateStakeTxn: Problem encoding response as JSON") + return + } +} + +func (fes *APIServer) CreateUnstakeTxn(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := UnstakeRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnstakeTxn: Problem parsing request body: %v", err)) + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CreateUnstakeTxn: TransactorPublicKeyBase58Check is required")) + return + } + transactorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnstakeTxn: Problem decoding TransactorPublicKeyBase58Check %s: %v", + requestData.TransactorPublicKeyBase58Check, err)) + return + } + + // Convert ValidatorPublicKeyBase58Check to ValidatorPublicKeyBytes + if requestData.ValidatorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CreateUnstakeTxn: ValidatorPublicKeyBase58Check is required")) + return + } + validatorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.ValidatorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnstakeTxn: Problem decoding ValidatorPublicKeyBase58Check %s: %v", + requestData.ValidatorPublicKeyBase58Check, err)) + return + } + + // Validate unstake amount nanos + if !requestData.UnstakeAmountNanos.IsUint64() { + _AddBadRequestError(ww, fmt.Sprint("CreateUnstakeTxn: UnstakeAmountNanos must be a uint64")) + return + } + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnstakeTxn: Problem fetching utxoView: %v", err)) + return + } + // Get staker and validator PKIDs + stakerPKID := utxoView.GetPKIDForPublicKey(transactorPublicKeyBytes) + validatorPKID := utxoView.GetPKIDForPublicKey(validatorPublicKeyBytes) + stakeEntry, err := utxoView.GetStakeEntry(validatorPKID.PKID, stakerPKID.PKID) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnstakeTxn: Problem fetching stake entry: %v", err)) + return + } + if requestData.UnstakeAmountNanos.Gt(stakeEntry.StakeAmountNanos) { + _AddBadRequestError(ww, fmt.Sprint("CreateUnstakeTxn: UnstakeAmountNanos cannot be greater than the current stake "+ + "amount")) + return + } + + // Parse ExtraData. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnstakeTxn: Problem parsing ExtraData: %v", err)) + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeUnstake, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprint("CreateUnstakeTxn: specified TransactionFees are invalid")) + return + } + + // Create the transaction. + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateUnstakeTxn( + transactorPublicKeyBytes, + &lib.UnstakeMetadata{ + ValidatorPublicKey: lib.NewPublicKey(validatorPublicKeyBytes), + UnstakeAmountNanos: requestData.UnstakeAmountNanos, + }, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CreateUnstakeTxn: Problem serializing transaction: %v", err)) + return + } + + res := StakeTxnResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, "CreateUnstakeTxn: Problem encoding response as JSON") + return + } +} + +func (fes *APIServer) CreateUnlockStakeTxn(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := UnlockStakeRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnlockStakeTxn: Problem parsing request body: %v", err)) + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CreateUnlockStakeTxn: TransactorPublicKeyBase58Check is required")) + return + } + transactorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnlockStakeTxn: Problem decoding TransactorPublicKeyBase58Check %s: %v", + requestData.TransactorPublicKeyBase58Check, err)) + return + } + + // Convert ValidatorPublicKeyBase58Check to ValidatorPublicKeyBytes + if requestData.ValidatorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CreateUnlockStakeTxn: ValidatorPublicKeyBase58Check is required")) + return + } + validatorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.ValidatorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnlockStakeTxn: Problem decoding ValidatorPublicKeyBase58Check %s: %v", + requestData.ValidatorPublicKeyBase58Check, err)) + return + } + + // Validate start and end epoch + if requestData.StartEpochNumber > requestData.EndEpochNumber { + _AddBadRequestError(ww, fmt.Sprint("CreateUnlockStakeTxn: StartEpochNumber cannot be greater than EndEpochNumber")) + return + } + + // Parse ExtraData. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateUnlockStakeTxn: Problem parsing ExtraData: %v", err)) + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeUnlockStake, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprint("CreateUnlockStakeTxn: specified TransactionFees are invalid")) + return + } + + // Create the transaction. + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateUnlockStakeTxn( + transactorPublicKeyBytes, + &lib.UnlockStakeMetadata{ + ValidatorPublicKey: lib.NewPublicKey(validatorPublicKeyBytes), + StartEpochNumber: requestData.StartEpochNumber, + EndEpochNumber: requestData.EndEpochNumber, + }, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CreateUnlockStakeTxn: Problem serializing transaction: %v", err)) + return + } + + res := StakeTxnResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, "CreateUnlockStakeTxn: Problem encoding response as JSON") + return + } +} + +// TODO: Implement the following GET endpoints: +// 1. GET stake entry given validator pub key & staker pub key +// 2. GET all stake entries given validator pub key +// 3. GET all stake entries given staker pub key +// 4. GET locked stake entry given validator pub key & staker pub key & locked at epoch number +// 5. GET all locked stake entries given validator pub key & staker pub key & optionally start and end epochs + +// Other functions to implement. +// 1. _convertStakeEntryToResponse() helper function to convert a StakeEntry to a StakeEntryResponse. +// 2. _convertLockedStakeEntryToResponse() helper function to convert a LockedStakeEntry to a LockedStakeEntryResponse. From 6b5ddf3a7336c0fef191e71daa8b210f636b387f Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 23 Jan 2024 14:45:54 -0500 Subject: [PATCH 22/84] Add GET endpoints for stake and locked stake entries (#525) Co-authored-by: Lazy Nina <> --- routes/constants.go | 1 + routes/server.go | 30 +++++ routes/stake.go | 321 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 331 insertions(+), 21 deletions(-) create mode 100644 routes/constants.go diff --git a/routes/constants.go b/routes/constants.go new file mode 100644 index 00000000..0db51ae5 --- /dev/null +++ b/routes/constants.go @@ -0,0 +1 @@ +package routes diff --git a/routes/server.go b/routes/server.go index 8cf6cb16..1d17ece5 100644 --- a/routes/server.go +++ b/routes/server.go @@ -321,6 +321,7 @@ const ( RoutePathStake = "/api/v0/stake" RoutePathUnstake = "/api/v0/unstake" RoutePathUnlockStake = "/api/v0/unlock-stake" + RoutePathLockedStake = "/api/v0/locked-stake" ) // APIServer provides the interface between the blockchain and things like the @@ -1330,6 +1331,29 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.CreateUnlockStakeTxn, PublicAccess, }, + { + "GetStakeForValidatorAndStaker", + []string{"GET"}, + RoutePathStake + "/" + makePublicKeyParamRegex(validatorPublicKeyBase58CheckKey) + "/" + + makePublicKeyParamRegex(stakerPublicKeyBase58CheckKey), + fes.GetStakeForValidatorAndStaker, + PublicAccess, + }, + { + "GetStakesForValidator", + []string{"GET"}, + RoutePathStake + "/validator/" + makePublicKeyParamRegex(validatorPublicKeyBase58CheckKey), + fes.GetStakesForValidator, + PublicAccess, + }, + { + "GetLockedStakeForValidatorAndStaker", + []string{"GET"}, + RoutePathLockedStake + "/" + makePublicKeyParamRegex(validatorPublicKeyBase58CheckKey) + "/" + + makePublicKeyParamRegex(stakerPublicKeyBase58CheckKey), + fes.GetLockedStakesForValidatorAndStaker, + PublicAccess, + }, // Jumio Routes { "JumioBegin", @@ -2842,3 +2866,9 @@ func (fes *APIServer) makePKIDMapJSONEncodable(restrictedKeysMap map[lib.PKID][] } return outputMap } + +const publicKeyParamRegex = "t?BC[1-9A-HJ-NP-Za-km-z]{51,53}" + +func makePublicKeyParamRegex(paramName string) string { + return fmt.Sprintf("{%s:%s}", paramName, publicKeyParamRegex) +} diff --git a/routes/stake.go b/routes/stake.go index 8b1d3aa9..583280b2 100644 --- a/routes/stake.go +++ b/routes/stake.go @@ -5,18 +5,48 @@ import ( "encoding/json" "fmt" "github.com/deso-protocol/core/lib" + "github.com/gorilla/mux" "github.com/holiman/uint256" "io" + "math" "net/http" + "strconv" ) type StakeRewardMethod string const ( - PayToBalance StakeRewardMethod = "PAY_TO_BALANCE" - Restake StakeRewardMethod = "RESTAKE" + PayToBalance StakeRewardMethod = "PAY_TO_BALANCE" + Restake StakeRewardMethod = "RESTAKE" + UnknownStakeRewardMethod StakeRewardMethod = "UNKNOWN_STAKE_REWARD_METHOD" ) +func (stakeRewardMethod StakeRewardMethod) String() string { + return string(stakeRewardMethod) +} + +func (stakeRewardMethod StakeRewardMethod) ToStakeRewardMethod() lib.StakingRewardMethod { + switch stakeRewardMethod { + case PayToBalance: + return lib.StakingRewardMethodPayToBalance + case Restake: + return lib.StakingRewardMethodRestake + default: + return lib.StakingRewardMethodUnknown + } +} + +func FromLibStakeRewardMethod(stakeRewardMethod lib.StakingRewardMethod) StakeRewardMethod { + switch stakeRewardMethod { + case lib.StakingRewardMethodPayToBalance: + return PayToBalance + case lib.StakingRewardMethodRestake: + return Restake + default: + return UnknownStakeRewardMethod + } +} + type StakeRequest struct { TransactorPublicKeyBase58Check string `safeForLogging:"true"` ValidatorPublicKeyBase58Check string `safeForLogging:"true"` @@ -59,7 +89,7 @@ type StakeTxnResponse struct { type StakeEntryResponse struct { StakerPublicKeyBase58Check string ValidatorPublicKeyBase58Check string - RewardMethod StakeRewardMethod + RewardMethod string StakeAmountNanos *uint256.Int ExtraData map[string]string } @@ -72,6 +102,16 @@ type LockedStakeEntryResponse struct { ExtraData map[string]string } +// Constants for query params +const ( + validatorPublicKeyBase58CheckKey = "validatorPublicKeyBase58Check" + stakerPublicKeyBase58CheckKey = "stakerPublicKeyBase58Check" + lockedAtEpochNumberKey = "lockedAtEpochNumber" + startEpochNumberKey = "startEpochNumber" + endEpochNumberKey = "endEpochNumber" +) + +// Stake constructs a transaction that stakes a given amount of DeSo. func (fes *APIServer) CreateStakeTxn(ww http.ResponseWriter, req *http.Request) { // Decode request body. decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) @@ -106,15 +146,8 @@ func (fes *APIServer) CreateStakeTxn(ww http.ResponseWriter, req *http.Request) } // Convert reward method string to enum. - var rewardMethod lib.StakingRewardMethod - switch requestData.RewardMethod { - case PayToBalance: - rewardMethod = lib.StakingRewardMethodPayToBalance - break - case Restake: - rewardMethod = lib.StakingRewardMethodRestake - break - default: + rewardMethod := requestData.RewardMethod.ToStakeRewardMethod() + if rewardMethod == lib.StakingRewardMethodUnknown { _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Invalid RewardMethod %s", requestData.RewardMethod)) return } @@ -200,6 +233,7 @@ func (fes *APIServer) CreateStakeTxn(ww http.ResponseWriter, req *http.Request) } } +// Unstake constructs a transaction that unstakes a staked entry. func (fes *APIServer) CreateUnstakeTxn(ww http.ResponseWriter, req *http.Request) { // Decode request body. decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) @@ -311,6 +345,7 @@ func (fes *APIServer) CreateUnstakeTxn(ww http.ResponseWriter, req *http.Request } } +// UnlockStake constructs a transaction that unlocks a locked stake entry. func (fes *APIServer) CreateUnlockStakeTxn(ww http.ResponseWriter, req *http.Request) { // Decode request body. decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) @@ -405,13 +440,257 @@ func (fes *APIServer) CreateUnlockStakeTxn(ww http.ResponseWriter, req *http.Req } } -// TODO: Implement the following GET endpoints: -// 1. GET stake entry given validator pub key & staker pub key -// 2. GET all stake entries given validator pub key -// 3. GET all stake entries given staker pub key -// 4. GET locked stake entry given validator pub key & staker pub key & locked at epoch number -// 5. GET all locked stake entries given validator pub key & staker pub key & optionally start and end epochs +// _stakeEntryToResponse converts the core lib.StakeEntry to a StakeEntryResponse +func _stakeEntryToResponse( + stakeEntry *lib.StakeEntry, params *lib.DeSoParams, utxoView *lib.UtxoView) *StakeEntryResponse { + stakerPublicKey := utxoView.GetPublicKeyForPKID(stakeEntry.StakerPKID) + validatorPublicKey := utxoView.GetPublicKeyForPKID(stakeEntry.ValidatorPKID) + return &StakeEntryResponse{ + StakerPublicKeyBase58Check: lib.Base58CheckEncode(stakerPublicKey, false, params), + ValidatorPublicKeyBase58Check: lib.Base58CheckEncode(validatorPublicKey, false, params), + RewardMethod: FromLibStakeRewardMethod(stakeEntry.RewardMethod).String(), + StakeAmountNanos: stakeEntry.StakeAmountNanos, + ExtraData: DecodeExtraDataMap(params, utxoView, stakeEntry.ExtraData), + } +} + +// GetStakeForValidatorAndStaker returns the stake entry for a given validator and staker +func (fes *APIServer) GetStakeForValidatorAndStaker(ww http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + validatorPublicKeyBase58Check, validatorExists := vars[validatorPublicKeyBase58CheckKey] + if !validatorExists { + _AddBadRequestError(ww, fmt.Sprint("GetStakeForValidatorAndStaker: validatorPublicKeyBase58Check is required")) + return + } + stakerPublicKeyBase58Check, stakerExists := vars[stakerPublicKeyBase58CheckKey] + if !stakerExists { + _AddBadRequestError(ww, fmt.Sprint("GetStakeForValidatorAndStaker: stakerPublicKeyBase58Check is required")) + return + } + + // Create UTXO View + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("GetStakeForValidatorAndStaker: Problem fetching utxoView: %v", err)) + return + } + + // Convert validator public key to bytes + validatorPKID, err := fes.getPKIDFromPublicKeyBase58Check(utxoView, validatorPublicKeyBase58Check) + if err != nil || validatorPKID == nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetStakeForValidatorAndStaker: Problem decoding validator public key: %v", err)) + return + } + + // Convert staker public key to bytes + stakerPKID, err := fes.getPKIDFromPublicKeyBase58Check(utxoView, stakerPublicKeyBase58Check) + if err != nil || stakerPKID == nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetStakeForValidatorAndStaker: Problem decoding staker public key: %v", err)) + return + } + + // Get the stake entry + stakeEntry, err := utxoView.GetStakeEntry(validatorPKID, stakerPKID) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("GetStakeForValidatorAndStaker: Problem fetching stake entry: %v", err)) + return + } + if stakeEntry == nil { + _AddNotFoundError(ww, fmt.Sprint("GetStakeForValidatorAndStaker: No stake entry found")) + return + } + + if err = json.NewEncoder(ww).Encode(_stakeEntryToResponse(stakeEntry, fes.Params, utxoView)); err != nil { + _AddInternalServerError(ww, "GetStakeForValidatorAndStaker: Problem encoding response as JSON") + return + } +} -// Other functions to implement. -// 1. _convertStakeEntryToResponse() helper function to convert a StakeEntry to a StakeEntryResponse. -// 2. _convertLockedStakeEntryToResponse() helper function to convert a LockedStakeEntry to a LockedStakeEntryResponse. +// GetStakesForValidator returns all stake entries for a given validator +func (fes *APIServer) GetStakesForValidator(ww http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + validatorPublicKeyBase58Check, validatorExists := vars[validatorPublicKeyBase58CheckKey] + if !validatorExists { + _AddBadRequestError(ww, fmt.Sprint("GetStakesForValidator: validatorPublicKeyBase58Check is required")) + return + } + + // Create UTXO View + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("GetStakesForValidator: Problem fetching utxoView: %v", err)) + return + } + + // Convert validator public key to bytes + validatorPKID, err := fes.getPKIDFromPublicKeyBase58Check(utxoView, validatorPublicKeyBase58Check) + if err != nil || validatorPKID == nil { + _AddBadRequestError(ww, fmt.Sprintf("GetStakesForValidator: Problem decoding validator public key: %v", err)) + return + } + + // Get the stake entries + stakeEntries, err := utxoView.GetStakeEntriesForValidatorPKID(validatorPKID) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("GetStakesForValidator: Problem fetching stake entries: %v", err)) + return + } + + // Convert to stake entry responses + var stakeEntryResponses []*StakeEntryResponse + for _, stakeEntry := range stakeEntries { + stakeEntryResponses = append(stakeEntryResponses, _stakeEntryToResponse(stakeEntry, fes.Params, utxoView)) + } + + // Encode response. + if err = json.NewEncoder(ww).Encode(stakeEntryResponses); err != nil { + _AddInternalServerError(ww, "GetStakesForValidator: Problem encoding response as JSON") + return + } +} + +// GetLockedStakesForValidatorAndStaker returns all locked stake entries for a given validator and staker +// If lockedAtEpochNumber is specified, only the locked stake entry that was locked at that epoch number is returned +// If startEpochNumber and endEpochNumber are specified, all locked stake entries that were locked between those. +// If none are provided, all locked stake entries are returned. +func (fes *APIServer) GetLockedStakesForValidatorAndStaker(ww http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + validatorPublicKeyBase58Check, validatorExists := vars[validatorPublicKeyBase58CheckKey] + if !validatorExists { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: validatorPublicKeyBase58Check is required")) + return + } + stakerPublicKeyBase58Check, stakerExists := vars[stakerPublicKeyBase58CheckKey] + if !stakerExists { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: stakerPublicKeyBase58Check is required")) + return + } + + // Create UTXO View + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem fetching utxoView: %v", err)) + return + } + + // Convert validator public key to bytes + validatorPKID, err := fes.getPKIDFromPublicKeyBase58Check(utxoView, validatorPublicKeyBase58Check) + if err != nil || validatorPKID == nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem decoding validator public key: %v", err)) + return + } + + // Convert staker public key to bytes + stakerPKID, err := fes.getPKIDFromPublicKeyBase58Check(utxoView, stakerPublicKeyBase58Check) + if err != nil || stakerPKID == nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem decoding staker public key: %v", err)) + return + } + + queryParamBytes, err := json.Marshal(req.URL.Query()) + + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem parsing query params: %v", err)) + return + } + + queryParams := make(map[string][]string) + + if err = json.Unmarshal(queryParamBytes, &queryParams); err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem parsing query params: %v", err)) + return + } + + var lockedStakeEntries []*lib.LockedStakeEntry + // First check for lockedAtEpochNumber + if len(queryParams[lockedAtEpochNumberKey]) != 0 { + lockedAtEpochNumber, err := strconv.ParseUint(queryParams[lockedAtEpochNumberKey][0], 10, 64) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem parsing lockedAtEpochNumber: %v", err)) + return + } + lockedStakeEntry, err := utxoView.GetLockedStakeEntry(validatorPKID, stakerPKID, lockedAtEpochNumber) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem fetching locked stake entry: %v", err)) + return + } + if lockedStakeEntry == nil { + _AddNotFoundError(ww, fmt.Sprint("GetLockedStakesForValidatorAndStaker: No locked stake entry found")) + return + } + lockedStakeEntries = append(lockedStakeEntries, lockedStakeEntry) + } else { + startEpochNumber := uint64(0) + endEpochNumber := uint64(math.MaxUint64) + if len(queryParams[startEpochNumberKey]) != 0 { + startEpochNumber, err = strconv.ParseUint(queryParams[startEpochNumberKey][0], 10, 64) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem parsing startEpochNumber: %v", err)) + return + } + } + if len(queryParams[endEpochNumberKey]) != 0 { + endEpochNumber, err = strconv.ParseUint(queryParams[endEpochNumberKey][0], 10, 64) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem parsing endEpochNumber: %v", err)) + return + } + } + if startEpochNumber > endEpochNumber { + _AddBadRequestError(ww, fmt.Sprint( + "GetLockedStakesForValidatorAndStaker: startEpochNumber cannot be greater than endEpochNumber")) + return + } + lockedStakeEntries, err = utxoView.GetLockedStakeEntriesInRange( + validatorPKID, stakerPKID, startEpochNumber, endEpochNumber) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "GetLockedStakesForValidatorAndStaker: Problem fetching locked stake entries: %v", err)) + return + } + if len(lockedStakeEntries) == 0 { + _AddNotFoundError(ww, fmt.Sprint("GetLockedStakesForValidatorAndStaker: No locked stake entries found")) + return + } + } + + // Convert locked stake entries to responses + var lockedStakeEntryResponses []*LockedStakeEntryResponse + for _, lockedStakeEntry := range lockedStakeEntries { + lockedStakeEntryResponses = append(lockedStakeEntryResponses, _lockedStakeEntryToResponse( + lockedStakeEntry, fes.Params, utxoView)) + } + + // Encode response. + if err = json.NewEncoder(ww).Encode(lockedStakeEntryResponses); err != nil { + _AddInternalServerError(ww, "GetLockedStakesForValidatorAndStaker: Problem encoding response as JSON") + return + } +} + +// _lockedStakeEntryToResponse converts the core lib.LockedStakeEntry to a LockedStakeEntryResponse +func _lockedStakeEntryToResponse( + lockedStakeEntry *lib.LockedStakeEntry, params *lib.DeSoParams, utxoView *lib.UtxoView) *LockedStakeEntryResponse { + stakerPublicKey := utxoView.GetPublicKeyForPKID(lockedStakeEntry.StakerPKID) + validatorPublicKey := utxoView.GetPublicKeyForPKID(lockedStakeEntry.ValidatorPKID) + return &LockedStakeEntryResponse{ + StakerPublicKeyBase58Check: lib.Base58CheckEncode(stakerPublicKey, false, params), + ValidatorPublicKeyBase58Check: lib.Base58CheckEncode(validatorPublicKey, false, params), + LockedAmountNanos: lockedStakeEntry.LockedAmountNanos, + LockedAtEpochNumber: lockedStakeEntry.LockedAtEpochNumber, + ExtraData: DecodeExtraDataMap(params, utxoView, lockedStakeEntry.ExtraData), + } +} From 91b9b8c3486f88fc33e3d2755042ec84089a0b22 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Wed, 24 Jan 2024 11:07:55 -0500 Subject: [PATCH 23/84] Add spending limits backend support for stake, unstake, unlock stake (#529) --- routes/transaction.go | 114 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/routes/transaction.go b/routes/transaction.go index d1eea6ec..a23dda95 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -3234,6 +3234,21 @@ type AccessGroupMemberLimitMapItem struct { OpCount uint64 } +type StakeLimitMapItem struct { + ValidatorPublicKeyBase58Check string + StakeLimit *uint256.Int +} + +type UnstakeLimitMapItem struct { + ValidatorPublicKeyBase58Check string + UnstakeLimit *uint256.Int +} + +type UnlockStakeLimitMapItem struct { + ValidatorPublicKeyBase58Check string + OpCount uint64 +} + // TransactionSpendingLimitResponse is a backend struct used to describe the TransactionSpendingLimit for a Derived key // in a way that can be JSON encoded/decoded. type TransactionSpendingLimitResponse struct { @@ -3265,6 +3280,12 @@ type TransactionSpendingLimitResponse struct { AccessGroupLimitMap []AccessGroupLimitMapItem // AccessGroupMemberLimitMap is a slice of AccessGroupMemberLimitMapItems. AccessGroupMemberLimitMap []AccessGroupMemberLimitMapItem + // StakeLimitMap is a slice of StakeLimitMapItems + StakeLimitMap []StakeLimitMapItem + // UnstakeLimitMap is a slice of UnstakeLimitMapItems + UnstakeLimitMap []UnstakeLimitMapItem + // UnlockStakeLimitMap is a slice of UnlockStakeLimitMapItems + UnlockStakeLimitMap []UnlockStakeLimitMapItem // ===== ENCODER MIGRATION lib.UnlimitedDerivedKeysMigration ===== // IsUnlimited determines whether this derived key is unlimited. An unlimited derived key can perform all transactions @@ -3614,6 +3635,54 @@ func TransactionSpendingLimitToResponse( } } + if len(transactionSpendingLimit.StakeLimitMap) > 0 { + for stakeLimitKey, stakeLimit := range transactionSpendingLimit.StakeLimitMap { + validatorPublicKey := utxoView.GetPublicKeyForPKID(&stakeLimitKey.ValidatorPKID) + validatorPublicKeyBase58Check := lib.Base58CheckEncode( + validatorPublicKey, false, params, + ) + transactionSpendingLimitResponse.StakeLimitMap = append( + transactionSpendingLimitResponse.StakeLimitMap, + StakeLimitMapItem{ + ValidatorPublicKeyBase58Check: validatorPublicKeyBase58Check, + StakeLimit: stakeLimit.Clone(), + }, + ) + } + } + + if len(transactionSpendingLimit.UnstakeLimitMap) > 0 { + for unstakeLimitKey, unstakeLimit := range transactionSpendingLimit.UnstakeLimitMap { + validatorPublicKey := utxoView.GetPublicKeyForPKID(&unstakeLimitKey.ValidatorPKID) + validatorPublicKeyBase58Check := lib.Base58CheckEncode( + validatorPublicKey, false, params, + ) + transactionSpendingLimitResponse.UnstakeLimitMap = append( + transactionSpendingLimitResponse.UnstakeLimitMap, + UnstakeLimitMapItem{ + ValidatorPublicKeyBase58Check: validatorPublicKeyBase58Check, + UnstakeLimit: unstakeLimit.Clone(), + }, + ) + } + } + + if len(transactionSpendingLimit.UnlockStakeLimitMap) > 0 { + for unlockStakeLimitKey, opCount := range transactionSpendingLimit.UnlockStakeLimitMap { + validatorPublicKey := utxoView.GetPublicKeyForPKID(&unlockStakeLimitKey.ValidatorPKID) + validatorPublicKeyBase58Check := lib.Base58CheckEncode( + validatorPublicKey, false, params, + ) + transactionSpendingLimitResponse.UnlockStakeLimitMap = append( + transactionSpendingLimitResponse.UnlockStakeLimitMap, + UnlockStakeLimitMapItem{ + ValidatorPublicKeyBase58Check: validatorPublicKeyBase58Check, + OpCount: opCount, + }, + ) + } + } + return transactionSpendingLimitResponse } @@ -3777,6 +3846,51 @@ func (fes *APIServer) TransactionSpendingLimitFromResponse( } } + if len(transactionSpendingLimitResponse.StakeLimitMap) > 0 { + transactionSpendingLimit.StakeLimitMap = make(map[lib.StakeLimitKey]*uint256.Int) + for _, stakeLimitMapItem := range transactionSpendingLimitResponse.StakeLimitMap { + validatorPublicKey, _, err := lib.Base58CheckDecode(stakeLimitMapItem.ValidatorPublicKeyBase58Check) + if err != nil { + return nil, err + } + validatorPKID := utxoView.GetPKIDForPublicKey(validatorPublicKey) + stakeLimitKey := lib.MakeStakeLimitKey( + validatorPKID.PKID, + ) + transactionSpendingLimit.StakeLimitMap[stakeLimitKey] = stakeLimitMapItem.StakeLimit.Clone() + } + } + + if len(transactionSpendingLimitResponse.UnstakeLimitMap) > 0 { + transactionSpendingLimit.UnstakeLimitMap = make(map[lib.StakeLimitKey]*uint256.Int) + for _, unstakeLimitMapItem := range transactionSpendingLimitResponse.UnstakeLimitMap { + validatorPublicKey, _, err := lib.Base58CheckDecode(unstakeLimitMapItem.ValidatorPublicKeyBase58Check) + if err != nil { + return nil, err + } + validatorPKID := utxoView.GetPKIDForPublicKey(validatorPublicKey) + unstakeLimitKey := lib.MakeStakeLimitKey( + validatorPKID.PKID, + ) + transactionSpendingLimit.UnstakeLimitMap[unstakeLimitKey] = unstakeLimitMapItem.UnstakeLimit.Clone() + } + } + + if len(transactionSpendingLimitResponse.UnlockStakeLimitMap) > 0 { + transactionSpendingLimit.UnlockStakeLimitMap = make(map[lib.StakeLimitKey]uint64) + for _, unlockStakeLimitMapItem := range transactionSpendingLimitResponse.UnlockStakeLimitMap { + validatorPublicKey, _, err := lib.Base58CheckDecode(unlockStakeLimitMapItem.ValidatorPublicKeyBase58Check) + if err != nil { + return nil, err + } + validatorPKID := utxoView.GetPKIDForPublicKey(validatorPublicKey) + unlockStakeLimitKey := lib.MakeStakeLimitKey( + validatorPKID.PKID, + ) + transactionSpendingLimit.UnlockStakeLimitMap[unlockStakeLimitKey] = unlockStakeLimitMapItem.OpCount + } + } + return transactionSpendingLimit, nil } From 0cf96c15c21c83b074a26f10790b37c908fe1ea6 Mon Sep 17 00:00:00 2001 From: tholonious <99746187+tholonious@users.noreply.github.com> Date: Wed, 31 Jan 2024 17:39:04 -0500 Subject: [PATCH 24/84] Update Block Header Timestamps to int64 (#535) --- routes/exchange.go | 6 +++--- routes/exchange_test.go | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/routes/exchange.go b/routes/exchange.go index a75cade4..5f035dbb 100644 --- a/routes/exchange.go +++ b/routes/exchange.go @@ -678,7 +678,7 @@ func APITransactionToResponse( if block != nil && block.Header != nil { ret.BlockInfo = &TransactionBlockInfo{ Height: block.Header.Height, - TimestampSecs: block.Header.GetTstampSecs(), + TimestampSecs: uint64(block.Header.GetTstampSecs()), } } @@ -1272,10 +1272,10 @@ type HeaderResponse struct { TransactionMerkleRootHex string // The unix timestamp (in seconds) specifying when this block was // mined. - TstampSecs uint64 + TstampSecs int64 // The unix timestamp (in nanoseconds) specifying when this block was // mined. - TstampNanoSecs uint64 + TstampNanoSecs int64 // The height of the block this header corresponds to. Height uint64 diff --git a/routes/exchange_test.go b/routes/exchange_test.go index d5c71937..c5f87556 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -4,10 +4,6 @@ import ( "bytes" "encoding/hex" "encoding/json" - chainlib "github.com/btcsuite/btcd/blockchain" - "github.com/deso-protocol/backend/config" - coreCmd "github.com/deso-protocol/core/cmd" - "github.com/deso-protocol/core/lib" "io" "log" "net/http" @@ -16,6 +12,11 @@ import ( "testing" "time" + chainlib "github.com/btcsuite/btcd/blockchain" + "github.com/deso-protocol/backend/config" + coreCmd "github.com/deso-protocol/core/cmd" + "github.com/deso-protocol/core/lib" + "github.com/dgraph-io/badger/v3" "github.com/stretchr/testify/assert" @@ -100,7 +101,7 @@ func NewLowDifficultyBlockchainWithParams(t *testing.T, params *lib.DeSoParams) Version: 0, PrevBlockHash: lib.MustDecodeHexBlockHash("0000000000000000000000000000000000000000000000000000000000000000"), TransactionMerkleRoot: lib.MustDecodeHexBlockHash("097158f0d27e6d10565c4dc696c784652c3380e0ff8382d3599a4d18b782e965"), - TstampNanoSecs: uint64(1560735050), + TstampNanoSecs: int64(1560735050), Height: uint64(0), Nonce: uint64(0), // No ExtraNonce is set in the genesis block From c11ca20fe3c285779aa1c6376c2d300b6b6d029c Mon Sep 17 00:00:00 2001 From: tholonious <99746187+tholonious@users.noreply.github.com> Date: Fri, 2 Feb 2024 11:58:46 -0500 Subject: [PATCH 25/84] Fix Backend To Run With Regtest PoS Node (#536) --- routes/exchange_test.go | 2 +- routes/transaction.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/routes/exchange_test.go b/routes/exchange_test.go index c5f87556..ad159f5f 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -101,7 +101,7 @@ func NewLowDifficultyBlockchainWithParams(t *testing.T, params *lib.DeSoParams) Version: 0, PrevBlockHash: lib.MustDecodeHexBlockHash("0000000000000000000000000000000000000000000000000000000000000000"), TransactionMerkleRoot: lib.MustDecodeHexBlockHash("097158f0d27e6d10565c4dc696c784652c3380e0ff8382d3599a4d18b782e965"), - TstampNanoSecs: int64(1560735050), + TstampNanoSecs: 1560735050, Height: uint64(0), Nonce: uint64(0), // No ExtraNonce is set in the genesis block diff --git a/routes/transaction.go b/routes/transaction.go index a23dda95..070af111 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -4101,7 +4101,6 @@ func (fes *APIServer) simulateSubmitTransaction(utxoView *lib.UtxoView, txn *lib return utxoView.ConnectTransaction( txn, txn.Hash(), - 0, bestHeight, 0, false, From 734d12efcfcf2d0fb2cb61f396a31010903a8297 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:41:14 -0500 Subject: [PATCH 26/84] Add txn construction and get endpoints for lockups (#526) * Add spending limits backend support for stake, unstake, unlock stake * Add txn construction and get endpoints for lockups * Add additional sanity checks to lockup endpoint. * Add txn construction and get endpoints for lockups * Add additional sanity checks to lockup endpoint. * Remove redundant profile entry response from LockedBalanceEntryResponse. * Add proper timestamp to simulateSubmitTransaction. * Apply suggestions from code review --------- Co-authored-by: Lazy Nina <> Co-authored-by: Jon Pollock --- routes/lockups.go | 733 ++++++++++++++++++++++++++++++++++++++++++ routes/server.go | 50 +++ routes/stake.go | 1 + routes/transaction.go | 42 ++- routes/user.go | 11 +- 5 files changed, 832 insertions(+), 5 deletions(-) create mode 100644 routes/lockups.go diff --git a/routes/lockups.go b/routes/lockups.go new file mode 100644 index 00000000..45d7f08f --- /dev/null +++ b/routes/lockups.go @@ -0,0 +1,733 @@ +package routes + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "github.com/deso-protocol/core/collections" + "github.com/deso-protocol/core/lib" + "github.com/gorilla/mux" + "github.com/holiman/uint256" + "io" + "net/http" + "reflect" + "time" +) + +type CumulativeLockedBalanceEntryResponse struct { + HODLerPublicKeyBase58Check string + ProfilePublicKeyBase58Check string + TotalLockedBaseUnits uint256.Int + UnlockableBaseUnits uint256.Int + UnvestedLockedBalanceEntries []*LockedBalanceEntryResponse + VestedLockedBalanceEntries []*LockedBalanceEntryResponse + ProfileEntryResponse *ProfileEntryResponse +} + +type LockedBalanceEntryResponse struct { + HODLerPublicKeyBase58Check string + ProfilePublicKeyBase58Check string + UnlockTimestampNanoSecs int64 + VestingEndTimestampNanoSecs int64 + BalanceBaseUnits uint256.Int +} + +func (fes *APIServer) _lockedBalanceEntryToResponse( + lockedBalanceEntry *lib.LockedBalanceEntry, utxoView *lib.UtxoView, params *lib.DeSoParams, +) *LockedBalanceEntryResponse { + hodlerPublicKey := utxoView.GetPublicKeyForPKID(lockedBalanceEntry.HODLerPKID) + profilePublicKey := utxoView.GetPublicKeyForPKID(lockedBalanceEntry.ProfilePKID) + return &LockedBalanceEntryResponse{ + HODLerPublicKeyBase58Check: lib.PkToString(hodlerPublicKey, params), + ProfilePublicKeyBase58Check: lib.PkToString(profilePublicKey, params), + UnlockTimestampNanoSecs: lockedBalanceEntry.UnlockTimestampNanoSecs, + VestingEndTimestampNanoSecs: lockedBalanceEntry.VestingEndTimestampNanoSecs, + BalanceBaseUnits: lockedBalanceEntry.BalanceBaseUnits, + } +} + +type LockupYieldCurvePointResponse struct { + ProfilePublicKeyBase58Check string + LockupDurationNanoSecs int64 + LockupYieldAPYBasisPoints uint64 + ProfileEntryResponse *ProfileEntryResponse +} + +func (fes *APIServer) _lockupYieldCurvePointToResponse( + lockupYieldCurvePoint *lib.LockupYieldCurvePoint, utxoView *lib.UtxoView, params *lib.DeSoParams, +) *LockupYieldCurvePointResponse { + profilePublicKey := utxoView.GetPublicKeyForPKID(lockupYieldCurvePoint.ProfilePKID) + profileEntry := utxoView.GetProfileEntryForPKID(lockupYieldCurvePoint.ProfilePKID) + profileEntryResponse := fes._profileEntryToResponse(profileEntry, utxoView) + return &LockupYieldCurvePointResponse{ + ProfilePublicKeyBase58Check: lib.PkToString(profilePublicKey, params), + LockupDurationNanoSecs: lockupYieldCurvePoint.LockupDurationNanoSecs, + LockupYieldAPYBasisPoints: lockupYieldCurvePoint.LockupYieldAPYBasisPoints, + ProfileEntryResponse: profileEntryResponse, + } +} + +type CoinLockupRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + ProfilePublicKeyBase58Check string `safeForLogging:"true"` + RecipientPublicKeyBase58Check string `safeForLogging:"true"` + UnlockTimestampNanoSecs int64 `safeForLogging:"true"` + VestingEndTimestampNanoSecs int64 `safeForLogging:"true"` + LockupAmountBaseUnits *uint256.Int `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type UpdateCoinLockupParamsRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + LockupYieldDurationNanoSecs int64 `safeForLogging:"true"` + LockupYieldAPYBasisPoints uint64 `safeForLogging:"true"` + RemoveYieldCurvePoint bool `safeForLogging:"true"` + NewLockupTransferRestrictions bool `safeForLogging:"true"` + LockupTransferRestrictionStatus TransferRestrictionStatusString `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type CoinLockupTransferRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + ProfilePublicKeyBase58Check string `safeForLogging:"true"` + RecipientPublicKeyBase58Check string `safeForLogging:"true"` + UnlockTimestampNanoSecs int64 `safeForLogging:"true"` + LockedCoinsToTransferBaseUnits *uint256.Int `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type CoinUnlockRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + ProfilePublicKeyBase58Check string `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + +type CoinLockResponse struct { + SpendAmountNanos uint64 + TotalInputNanos uint64 + ChangeAmountNanos uint64 + FeeNanos uint64 + Transaction *lib.MsgDeSoTxn + TransactionHex string + TxnHashHex string +} + +func (fes *APIServer) CoinLockup(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := CoinLockupRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: Problem parsing request body: %v", err)) + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CoinLockup: TransactorPublicKeyBase58Check is required")) + return + } + transactorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: Problem decoding TransactorPublicKeyBase58Check %s: %v", + requestData.TransactorPublicKeyBase58Check, err)) + return + } + + // Convert ProfilePublicKeyBase58Check to ProfilePublicKeyBytes + if requestData.ProfilePublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CoinLockup: ProfilePublicKeyBase58Check is required")) + return + } + profilePublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.ProfilePublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: Problem decoding ProfilePublicKeyBase58Check %s: %v", + requestData.ProfilePublicKeyBase58Check, err)) + return + + } + + // Convert RecipientPublicKeyBase58Check to RecipientPublicKeyBytes if it exists + var recipientPublicKeyBytes []byte + if requestData.RecipientPublicKeyBase58Check != "" { + recipientPublicKeyBytes, _, err = lib.Base58CheckDecode(requestData.RecipientPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: Problem decoding RecipientPublicKeyBase58Check %s: %v", + requestData.RecipientPublicKeyBase58Check, err)) + return + } + } + + // Sanity check that the lockup appears to occur in the future. + currentTimestampNanoSecs := time.Now().UnixNano() + if requestData.UnlockTimestampNanoSecs < currentTimestampNanoSecs { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: The unlock timestamp cannot be in the past "+ + "(unlock timestamp: %d, current timestamp: %d)\n", + requestData.UnlockTimestampNanoSecs, currentTimestampNanoSecs)) + return + } + + // Sanity check that the vested lockup does not go into the past. + if requestData.UnlockTimestampNanoSecs > requestData.VestingEndTimestampNanoSecs { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: Vested lockups cannot vest into the past "+ + "(unlock timestamp: %d, vesting end timestamp: %d\n", + requestData.UnlockTimestampNanoSecs, requestData.VestingEndTimestampNanoSecs)) + return + } + + // Sanity check that the lockup request amount is non-zero. + if requestData.LockupAmountBaseUnits.IsZero() { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: Cannot lockup an amount of zero\n")) + return + } + + // Encode the extra data. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: Problem encoding ExtraData: %v", err)) + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeCoinLockup, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: specified TransactionFees are invalid: %v", err)) + return + } + + // Create transaction + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateCoinLockupTxn( + transactorPublicKeyBytes, + profilePublicKeyBytes, + recipientPublicKeyBytes, + requestData.UnlockTimestampNanoSecs, + requestData.VestingEndTimestampNanoSecs, + requestData.LockupAmountBaseUnits, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockup: Problem creating txn: %v", err)) + return + } + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CoinLockup: Problem serializing txn: %v", err)) + return + } + + res := CoinLockResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CoinLockup: Problem encoding response as JSON: %v", err)) + return + } +} + +func (fes *APIServer) UpdateCoinLockupParams(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := UpdateCoinLockupParamsRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("UpdateCoinLockupParams: Problem parsing request body: %v", err)) + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("UpdateCoinLockupParams: TransactorPublicKeyBase58Check is required")) + return + } + transactorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("UpdateCoinLockupParams: Problem decoding TransactorPublicKeyBase58Check %s: %v", + requestData.TransactorPublicKeyBase58Check, err)) + return + } + + var transferRestrictionStatus lib.TransferRestrictionStatus + if requestData.NewLockupTransferRestrictions { + switch requestData.LockupTransferRestrictionStatus { + case TransferRestrictionStatusStringUnrestricted: + transferRestrictionStatus = lib.TransferRestrictionStatusUnrestricted + case TransferRestrictionStatusStringProfileOwnerOnly: + transferRestrictionStatus = lib.TransferRestrictionStatusProfileOwnerOnly + case TransferRestrictionStatusStringDAOMembersOnly: + transferRestrictionStatus = lib.TransferRestrictionStatusDAOMembersOnly + case TransferRestrictionStatusStringPermanentlyUnrestricted: + transferRestrictionStatus = lib.TransferRestrictionStatusPermanentlyUnrestricted + default: + _AddBadRequestError(ww, fmt.Sprintf( + "UpdateCoinLockupParams: TransferRestrictionStatus \"%v\" not supported", + requestData.LockupTransferRestrictionStatus)) + return + } + } + + // Parse extra data. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("UpdateCoinLockupParams: Problem encoding ExtraData: %v", err)) + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeUpdateCoinLockupParams, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("UpdateCoinLockupParams: specified TransactionFees are invalid: %v", err)) + return + } + + // Create transaction + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateUpdateCoinLockupParamsTxn( + transactorPublicKeyBytes, + requestData.LockupYieldDurationNanoSecs, + requestData.LockupYieldAPYBasisPoints, + requestData.RemoveYieldCurvePoint, + requestData.NewLockupTransferRestrictions, + transferRestrictionStatus, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("UpdateCoinLockupParams: Problem creating txn: %v", err)) + return + } + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("UpdateCoinLockupParams: Problem serializing txn: %v", err)) + return + } + + res := CoinLockResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, fmt.Sprintf("UpdateCoinLockupParams: Problem encoding response as JSON: %v", err)) + return + } +} + +func (fes *APIServer) CoinLockupTransfer(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := CoinLockupTransferRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockupTransfer: Problem parsing request body: %v", err)) + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CoinLockupTransfer: TransactorPublicKeyBase58Check is required")) + return + } + transactorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "CoinLockupTransfer: Problem decoding TransactorPublicKeyBase58Check %s: %v", + requestData.TransactorPublicKeyBase58Check, err)) + return + } + + // Convert ProfilePublicKeyBase58Check to ProfilePublicKeyBytes + if requestData.ProfilePublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CoinLockupTransfer: ProfilePublicKeyBase58Check is required")) + return + } + profilePublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.ProfilePublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockupTransfer: Problem decoding ProfilePublicKeyBase58Check %s: %v", + requestData.ProfilePublicKeyBase58Check, err)) + return + } + + // Convert RecipientPublicKeyBase58Check to RecipientPublicKeyBytes + if requestData.RecipientPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CoinLockupTransfer: RecipientPublicKeyBase58Check is required")) + return + } + recipientPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.RecipientPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockupTransfer: Problem decoding RecipientPublicKeyBase58Check %s: %v", + requestData.RecipientPublicKeyBase58Check, err)) + return + } + + // Check to ensure the recipient is different than the sender. + if reflect.DeepEqual(recipientPublicKeyBytes, transactorPublicKeyBytes) { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockupTransfer: Sender cannot be receiver of a transfer")) + return + } + + // Parse extra data. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockupTransfer: Problem encoding ExtraData: %v", err)) + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeCoinLockupTransfer, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockupTransfer: specified TransactionFees are invalid: %v", err)) + return + } + + // Create transaction + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateCoinLockupTransferTxn( + transactorPublicKeyBytes, + recipientPublicKeyBytes, + profilePublicKeyBytes, + requestData.UnlockTimestampNanoSecs, + requestData.LockedCoinsToTransferBaseUnits, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinLockupTransfer: Problem creating txn: %v", err)) + return + } + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CoinLockupTransfer: Problem serializing txn: %v", err)) + return + } + + res := CoinLockResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CoinLockupTransfer: Problem encoding response as JSON: %v", err)) + return + } +} + +func (fes *APIServer) CoinUnlock(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := CoinUnlockRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinUnlock: Problem parsing request body: %v", err)) + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CoinUnlock: TransactorPublicKeyBase58Check is required")) + return + } + transactorPublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinUnlock: Problem decoding TransactorPublicKeyBase58Check %s: %v", + requestData.TransactorPublicKeyBase58Check, err)) + return + } + + // Convert ProfilePublicKeyBase58Check to ProfilePublicKeyBytes + if requestData.ProfilePublicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprint("CoinUnlock: ProfilePublicKeyBase58Check is required")) + return + } + profilePublicKeyBytes, _, err := lib.Base58CheckDecode(requestData.ProfilePublicKeyBase58Check) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinUnlock: Problem decoding ProfilePublicKeyBase58Check %s: %v", + requestData.ProfilePublicKeyBase58Check, err)) + return + } + + // Parse extra data. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinUnlock: Problem encoding ExtraData: %v", err)) + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeCoinUnlock, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinUnlock: specified TransactionFees are invalid: %v", err)) + return + } + + // Create transaction + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateCoinUnlockTxn( + transactorPublicKeyBytes, + profilePublicKeyBytes, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CoinUnlock: Problem creating txn: %v", err)) + return + } + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CoinUnlock: Problem serializing txn: %v", err)) + return + } + + res := CoinLockResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, fmt.Sprintf("CoinUnlock: Problem encoding response as JSON: %v", err)) + return + } +} + +// GET lockup yield curve points for a profile by public key +func (fes *APIServer) LockedYieldCurvePoints(ww http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + publicKeyBase58Check := vars[publicKeyBase58CheckKey] + + if publicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprintf("LockedYieldCurvePoints: PublicKeyBase58Check is required")) + return + } + + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("LockedYieldCurvePoints: Problem getting utxoView: %v", err)) + return + } + + // Decode public key + pkid, err := fes.getPKIDFromPublicKeyBase58Check(utxoView, publicKeyBase58Check) + if err != nil || pkid == nil { + _AddBadRequestError(ww, fmt.Sprintf("LockedYieldCurvePoints: Problem decoding public key: %v", err)) + return + } + + // Get locked yield curve points + yieldCurvePointsMap, err := utxoView.GetAllYieldCurvePoints(pkid) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("LockedYieldCurvePoints: Problem getting yield curve points: %v", err)) + return + } + + var allYieldCurvePoints []*LockupYieldCurvePointResponse + for _, yieldCurvePoint := range yieldCurvePointsMap { + if yieldCurvePoint.IsDeleted() { + continue + } + allYieldCurvePoints = append(allYieldCurvePoints, + fes._lockupYieldCurvePointToResponse(yieldCurvePoint, utxoView, fes.Params)) + } + + sortedYieldCurvePoints := collections.SortStable(allYieldCurvePoints, + func(ii *LockupYieldCurvePointResponse, jj *LockupYieldCurvePointResponse) bool { + return ii.LockupDurationNanoSecs < jj.LockupDurationNanoSecs + }) + + if err = json.NewEncoder(ww).Encode(sortedYieldCurvePoints); err != nil { + _AddInternalServerError(ww, fmt.Sprintf("LockedYieldCurvePoints: Problem encoding response as JSON: %v", err)) + return + } +} + +// GET all locked balance entries held by a HODLer public key +func (fes *APIServer) LockedBalanceEntries(ww http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + publicKeyBase58Check := vars[publicKeyBase58CheckKey] + + if publicKeyBase58Check == "" { + _AddBadRequestError(ww, fmt.Sprintf("LockedBalanceEntriesHeldByPublicKey: PublicKeyBase58Check is required")) + return + } + + // Create an augmented UTXO view to include uncomitted transactions. + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("LockedBalanceEntriesHeldByPublicKey: Problem getting utxoView: %v", err)) + return + } + + // Decode public key + pkid, err := fes.getPKIDFromPublicKeyBase58Check(utxoView, publicKeyBase58Check) + if err != nil || pkid == nil { + _AddBadRequestError(ww, fmt.Sprintf("LockedBalanceEntriesHeldByPublicKey: Problem decoding public key: %v", err)) + return + } + + // Get all locked balance entries for a user. + lockedBalanceEntries, err := utxoView.GetAllLockedBalanceEntriesForHodlerPKID(pkid) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("LockedBalanceEntries: Problem getting locked balance entries: %v", err)) + return + } + + // Split the locked balance entries based on the creator. + creatorPKIDToCumulativeLockedBalanceEntryResponse := make(map[lib.PKID]*CumulativeLockedBalanceEntryResponse) + currentTimestampNanoSecs := time.Now().UnixNano() + for _, lockedBalanceEntry := range lockedBalanceEntries { + // Check if we need to initialize the cumulative response. + if _, exists := creatorPKIDToCumulativeLockedBalanceEntryResponse[*lockedBalanceEntry.ProfilePKID]; !exists { + hodlerPublicKey := utxoView.GetPublicKeyForPKID(lockedBalanceEntry.HODLerPKID) + profilePublicKey := utxoView.GetPublicKeyForPKID(lockedBalanceEntry.ProfilePKID) + profileEntry := utxoView.GetProfileEntryForPKID(lockedBalanceEntry.ProfilePKID) + profileEntryResponse := fes._profileEntryToResponse(profileEntry, utxoView) + + creatorPKIDToCumulativeLockedBalanceEntryResponse[*lockedBalanceEntry.ProfilePKID] = + &CumulativeLockedBalanceEntryResponse{ + HODLerPublicKeyBase58Check: lib.PkToString(hodlerPublicKey, fes.Params), + ProfilePublicKeyBase58Check: lib.PkToString(profilePublicKey, fes.Params), + TotalLockedBaseUnits: uint256.Int{}, + UnlockableBaseUnits: uint256.Int{}, + UnvestedLockedBalanceEntries: []*LockedBalanceEntryResponse{}, + VestedLockedBalanceEntries: []*LockedBalanceEntryResponse{}, + ProfileEntryResponse: profileEntryResponse, + } + } + + // Get the existing cumulative response. + cumulativeResponse := creatorPKIDToCumulativeLockedBalanceEntryResponse[*lockedBalanceEntry.ProfilePKID] + + // Update the total locked base units. + // NOTE: It's possible to create multiple locked balance entries that are impossible to unlock due to overflow. + // As such, if the addition triggers an overflow we will just ignore adding more and use the max Uint256. + var newTotalLockedBaseUnits *uint256.Int + if uint256.NewInt().Sub( + lib.MaxUint256, + &cumulativeResponse.TotalLockedBaseUnits).Lt(&lockedBalanceEntry.BalanceBaseUnits) { + newTotalLockedBaseUnits = lib.MaxUint256 + } else { + newTotalLockedBaseUnits = uint256.NewInt().Add( + &cumulativeResponse.TotalLockedBaseUnits, + &lockedBalanceEntry.BalanceBaseUnits) + } + + // Compute how much (if any) is unlockable in the give entry. + unlockableBaseUnitsFromEntry := uint256.NewInt() + newTotalUnlockableBaseUnits := uint256.NewInt() + if lockedBalanceEntry.UnlockTimestampNanoSecs < currentTimestampNanoSecs { + // Check if the locked balance entry is unvested or vested. + if lockedBalanceEntry.UnlockTimestampNanoSecs == lockedBalanceEntry.VestingEndTimestampNanoSecs { + unlockableBaseUnitsFromEntry = &lockedBalanceEntry.BalanceBaseUnits + } else { + unlockableBaseUnitsFromEntry, err = + lib.CalculateVestedEarnings(lockedBalanceEntry, currentTimestampNanoSecs) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("LockedBalanceEntries: Problem computing vested earnings: %v", err)) + return + } + } + } + if uint256.NewInt().Sub( + lib.MaxUint256, + &cumulativeResponse.UnlockableBaseUnits).Lt(unlockableBaseUnitsFromEntry) { + newTotalUnlockableBaseUnits = lib.MaxUint256 + } else { + newTotalUnlockableBaseUnits = uint256.NewInt().Add( + &cumulativeResponse.UnlockableBaseUnits, + unlockableBaseUnitsFromEntry) + } + + // Update the cumulative response. + cumulativeResponse.TotalLockedBaseUnits = *newTotalLockedBaseUnits + cumulativeResponse.UnlockableBaseUnits = *newTotalUnlockableBaseUnits + if lockedBalanceEntry.UnlockTimestampNanoSecs == lockedBalanceEntry.VestingEndTimestampNanoSecs { + cumulativeResponse.UnvestedLockedBalanceEntries = append( + cumulativeResponse.UnvestedLockedBalanceEntries, + fes._lockedBalanceEntryToResponse(lockedBalanceEntry, utxoView, fes.Params)) + } else { + cumulativeResponse.VestedLockedBalanceEntries = append( + cumulativeResponse.VestedLockedBalanceEntries, + fes._lockedBalanceEntryToResponse(lockedBalanceEntry, utxoView, fes.Params)) + } + } + + // Create a list of the cumulative locked balance entries and sort based on amount locked. + var cumulativeLockedBalanceEntryResponses []*CumulativeLockedBalanceEntryResponse + for _, cumulativeResponse := range creatorPKIDToCumulativeLockedBalanceEntryResponse { + cumulativeLockedBalanceEntryResponses = append( + cumulativeLockedBalanceEntryResponses, cumulativeResponse) + } + + // Sort the response based on the amount locked. + sortedCumulativeResponses := collections.SortStable(cumulativeLockedBalanceEntryResponses, + func(ii *CumulativeLockedBalanceEntryResponse, jj *CumulativeLockedBalanceEntryResponse) bool { + return ii.TotalLockedBaseUnits.Lt(&jj.TotalLockedBaseUnits) + }) + + // Encode and return the responses. + if err = json.NewEncoder(ww).Encode(sortedCumulativeResponses); err != nil { + _AddInternalServerError(ww, + fmt.Sprintf("LockedBalanceEntries: Problem encoding response as JSON: %v", err)) + return + } +} diff --git a/routes/server.go b/routes/server.go index 1d17ece5..77eddf69 100644 --- a/routes/server.go +++ b/routes/server.go @@ -322,6 +322,14 @@ const ( RoutePathUnstake = "/api/v0/unstake" RoutePathUnlockStake = "/api/v0/unlock-stake" RoutePathLockedStake = "/api/v0/locked-stake" + + // lockups.go + RoutePathCoinLockup = "/api/v0/coin-lockup" + RoutePathUpdateCoinLockupParams = "/api/v0/update-coin-lockup-params" + RoutePathCoinLockupTransfer = "/api/v0/coin-lockup-transfer" + RoutePathCoinUnlock = "/api/v0/coin-unlock" + RoutePathLockupYieldCurvePoints = "/api/v0/lockup-yield-curve-points" + RoutePathLockedBalanceEntries = "/api/v0/locked-balance-entries" ) // APIServer provides the interface between the blockchain and things like the @@ -1354,6 +1362,48 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.GetLockedStakesForValidatorAndStaker, PublicAccess, }, + { + "CoinLockup", + []string{"POST", "OPTIONS"}, + RoutePathCoinLockup, + fes.CoinLockup, + PublicAccess, + }, + { + "UpdateCoinLockupParams", + []string{"POST", "OPTIONS"}, + RoutePathUpdateCoinLockupParams, + fes.UpdateCoinLockupParams, + PublicAccess, + }, + { + "CoinLockupTransfer", + []string{"POST", "OPTIONS"}, + RoutePathCoinLockupTransfer, + fes.CoinLockupTransfer, + PublicAccess, + }, + { + "CoinUnlock", + []string{"POST", "OPTIONS"}, + RoutePathCoinUnlock, + fes.CoinUnlock, + PublicAccess, + }, + { + "LockedYieldCurvePoints", + []string{"GET"}, + RoutePathLockupYieldCurvePoints + "/" + makePublicKeyParamRegex(publicKeyBase58CheckKey), + fes.LockedYieldCurvePoints, + PublicAccess, + }, + { + "LockedBalanceEntries", + []string{"GET"}, + RoutePathLockedBalanceEntries + "/" + makePublicKeyParamRegex(publicKeyBase58CheckKey), + fes.LockedBalanceEntries, + PublicAccess, + }, // Jumio Routes { "JumioBegin", diff --git a/routes/stake.go b/routes/stake.go index 583280b2..891d9c74 100644 --- a/routes/stake.go +++ b/routes/stake.go @@ -109,6 +109,7 @@ const ( lockedAtEpochNumberKey = "lockedAtEpochNumber" startEpochNumberKey = "startEpochNumber" endEpochNumberKey = "endEpochNumber" + publicKeyBase58CheckKey = "publicKeyBase58Check" ) // Stake constructs a transaction that stakes a given amount of DeSo. diff --git a/routes/transaction.go b/routes/transaction.go index 070af111..797401ac 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -3249,6 +3249,13 @@ type UnlockStakeLimitMapItem struct { OpCount uint64 } +type LockupLimitMapItem struct { + ProfilePublicKeyBase58Check string + ScopeType lib.LockupLimitScopeTypeString + Operation lib.LockupLimitOperationString + OpCount uint64 +} + // TransactionSpendingLimitResponse is a backend struct used to describe the TransactionSpendingLimit for a Derived key // in a way that can be JSON encoded/decoded. type TransactionSpendingLimitResponse struct { @@ -3286,6 +3293,8 @@ type TransactionSpendingLimitResponse struct { UnstakeLimitMap []UnstakeLimitMapItem // UnlockStakeLimitMap is a slice of UnlockStakeLimitMapItems UnlockStakeLimitMap []UnlockStakeLimitMapItem + // LockupLimitMap is a slice of LockupLimitMapItems + LockupLimitMap []LockupLimitMapItem // ===== ENCODER MIGRATION lib.UnlimitedDerivedKeysMigration ===== // IsUnlimited determines whether this derived key is unlimited. An unlimited derived key can perform all transactions @@ -3683,6 +3692,21 @@ func TransactionSpendingLimitToResponse( } } + if len(transactionSpendingLimit.LockupLimitMap) > 0 { + for lockupLimitKey, opCount := range transactionSpendingLimit.LockupLimitMap { + publicKeyBytes := utxoView.GetPublicKeyForPKID(&lockupLimitKey.ProfilePKID) + publicKeyBase58Check := lib.Base58CheckEncode(publicKeyBytes, false, params) + transactionSpendingLimitResponse.LockupLimitMap = append( + transactionSpendingLimitResponse.LockupLimitMap, + LockupLimitMapItem{ + ProfilePublicKeyBase58Check: publicKeyBase58Check, + ScopeType: lockupLimitKey.ScopeType.ToScopeString(), + Operation: lockupLimitKey.Operation.ToOperationString(), + OpCount: opCount, + }) + } + } + return transactionSpendingLimitResponse } @@ -3890,6 +3914,21 @@ func (fes *APIServer) TransactionSpendingLimitFromResponse( transactionSpendingLimit.UnlockStakeLimitMap[unlockStakeLimitKey] = unlockStakeLimitMapItem.OpCount } } + if len(transactionSpendingLimitResponse.LockupLimitMap) > 0 { + transactionSpendingLimit.LockupLimitMap = make(map[lib.LockupLimitKey]uint64) + for _, lockupLimitMapItem := range transactionSpendingLimitResponse.LockupLimitMap { + profilePublicKey, _, err := lib.Base58CheckDecode(lockupLimitMapItem.ProfilePublicKeyBase58Check) + if err != nil { + return nil, err + } + pkidEntry := utxoView.GetPKIDForPublicKey(profilePublicKey) + transactionSpendingLimit.LockupLimitMap[lib.MakeLockupLimitKey( + *pkidEntry.PKID, + lockupLimitMapItem.ScopeType.ToScopeType(), + lockupLimitMapItem.Operation.ToOperationType(), + )] = lockupLimitMapItem.OpCount + } + } return transactionSpendingLimit, nil } @@ -4098,11 +4137,12 @@ func (fes *APIServer) GetTransactionSpending(ww http.ResponseWriter, req *http.R func (fes *APIServer) simulateSubmitTransaction(utxoView *lib.UtxoView, txn *lib.MsgDeSoTxn) (_utxoOperations []*lib.UtxoOperation, _totalInput uint64, _totalOutput uint64, _fees uint64, _err error) { bestHeight := fes.blockchain.BlockTip().Height + 1 + bytes, _ := txn.ToBytes(false) return utxoView.ConnectTransaction( txn, txn.Hash(), bestHeight, - 0, + time.Now().UnixNano(), false, false, ) diff --git a/routes/user.go b/routes/user.go index 62a2e24d..410a94d2 100644 --- a/routes/user.go +++ b/routes/user.go @@ -641,10 +641,11 @@ type CoinEntryResponse struct { } type DAOCoinEntryResponse struct { - NumberOfHolders uint64 - CoinsInCirculationNanos uint256.Int - MintingDisabled bool - TransferRestrictionStatus TransferRestrictionStatusString + NumberOfHolders uint64 + CoinsInCirculationNanos uint256.Int + MintingDisabled bool + TransferRestrictionStatus TransferRestrictionStatusString + LockupTransferRestrictionStatus TransferRestrictionStatusString } // GetProfiles ... @@ -1060,6 +1061,8 @@ func (fes *APIServer) _profileEntryToResponse(profileEntry *lib.ProfileEntry, ut MintingDisabled: profileEntry.DAOCoinEntry.MintingDisabled, TransferRestrictionStatus: getTransferRestrictionStatusStringFromTransferRestrictionStatus( profileEntry.DAOCoinEntry.TransferRestrictionStatus), + LockupTransferRestrictionStatus: getTransferRestrictionStatusStringFromTransferRestrictionStatus( + profileEntry.DAOCoinEntry.LockupTransferRestrictionStatus), }, CoinPriceDeSoNanos: coinPriceDeSoNanos, CoinPriceBitCloutNanos: coinPriceDeSoNanos, From 7151d337fa506610aa8d7295f340c4c4f0fc4d19 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:42:32 -0500 Subject: [PATCH 27/84] Add Unjail Validator endpoint (#532) --- routes/server.go | 7 ++++ routes/validators.go | 81 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/routes/server.go b/routes/server.go index 77eddf69..e5531599 100644 --- a/routes/server.go +++ b/routes/server.go @@ -1311,6 +1311,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.UnregisterAsValidator, PublicAccess, }, + { + "UnjailValidator", + []string{"POST", "OPTIONS"}, + RoutePathValidators + "/unjail", + fes.UnjailValidator, + PublicAccess, + }, { "GetValidatorByPublicKeyBase58Check", []string{"GET"}, diff --git a/routes/validators.go b/routes/validators.go index c86e0afb..8b447ebf 100644 --- a/routes/validators.go +++ b/routes/validators.go @@ -31,6 +31,13 @@ type UnregisterAsValidatorRequest struct { TransactionFees []TransactionFee `safeForLogging:"true"` } +type UnjailValidatorRequest struct { + TransactorPublicKeyBase58Check string `safeForLogging:"true"` + ExtraData map[string]string `safeForLogging:"true"` + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` + TransactionFees []TransactionFee `safeForLogging:"true"` +} + type ValidatorTxnResponse struct { SpendAmountNanos uint64 TotalInputNanos uint64 @@ -229,6 +236,80 @@ func (fes *APIServer) UnregisterAsValidator(ww http.ResponseWriter, req *http.Re } } +func (fes *APIServer) UnjailValidator(ww http.ResponseWriter, req *http.Request) { + // Decode request body. + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := UnjailValidatorRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, "UnjailValidator: problem parsing request body") + return + } + + // Convert TransactorPublicKeyBase58Check to TransactorPublicKeyBytes. + if requestData.TransactorPublicKeyBase58Check == "" { + _AddBadRequestError(ww, "UnjailValidator: must provide a TransactorPublicKeyBase58Check") + return + } + transactorPublicKeyBytes, err := GetPubKeyBytesFromBase58Check(requestData.TransactorPublicKeyBase58Check) + if err != nil { + _AddInternalServerError(ww, "UnjailValidator: problem getting public key for the transactor") + return + } + + // Parse ExtraData. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, "UnjailValidator: invalid ExtraData provided") + return + } + + // Compute the additional transaction fees as specified + // by the request body and the node-level fees. + additionalOutputs, err := fes.getTransactionFee( + lib.TxnTypeUnjailValidator, + transactorPublicKeyBytes, + requestData.TransactionFees, + ) + if err != nil { + _AddBadRequestError(ww, "UnjailValidator: specified TransactionFees are invalid") + return + } + + // Create transaction. + txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateUnjailValidatorTxn( + transactorPublicKeyBytes, + &lib.UnjailValidatorMetadata{}, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddInternalServerError(ww, fmt.Sprintf("UnjailValidator: problem creating txn: %v", err)) + return + } + + // Construct response. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddInternalServerError(ww, "UnjailValidator: problem encoding txn to bytes") + return + } + res := ValidatorTxnResponse{ + SpendAmountNanos: totalInput - changeAmount - fees, + TotalInputNanos: totalInput, + ChangeAmountNanos: changeAmount, + FeeNanos: fees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + TxnHashHex: txn.Hash().String(), + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, "UnjailValidator: problem encoding response as JSON") + return + } +} + func (fes *APIServer) GetValidatorByPublicKeyBase58Check(ww http.ResponseWriter, req *http.Request) { // Parse ValidatorPublicKeyBase58Check from URL. vars := mux.Vars(req) From 698a0bf523420a5c81c29d609a6e33044a341a73 Mon Sep 17 00:00:00 2001 From: tholonious <99746187+tholonious@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:57:45 -0500 Subject: [PATCH 28/84] feature/pos-syncing-and-steady-state (#537) * Regtest PoS Validator Support * Fix n0_test script --- .gitignore | 3 ++- scripts/nodes/n0_test | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 5851a585..0ff977e4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ local_scripts/* backend .idea -mem.log \ No newline at end of file +.vscode +mem.log diff --git a/scripts/nodes/n0_test b/scripts/nodes/n0_test index b12c2682..2da232ad 100755 --- a/scripts/nodes/n0_test +++ b/scripts/nodes/n0_test @@ -13,6 +13,7 @@ DATE=`date +%Y%m%d-%H:%M:%S-%N` # * 13UkvpJXdLWE4p68n4MAK6zQntQ1RHixyM rm /tmp/main.*.log +rm -rf /tmp/n0_test_00000 # "-gcflags=”all=-N -l" was added to get GoLand debugger (Delve) to work, see # https://blog.jetbrains.com/go/2019/02/06/debugging-with-goland-getting-started/ @@ -20,7 +21,7 @@ rm /tmp/main.*.log # "If you are running with Go 1.10 or newer, you need to add ` -gcflags=”all=-N -l” ` # to the ` go build ` command." -(cd ../../ && go build -o backend -gcflags="all=-N -l" main.go && ./backend run \ +(cd ../../ && go build -o backend -gcflags="all=-N -l" -tags="relic" main.go && ./backend run \ --glog-v=0 \ --glog-vmodule="*api*=0,*bitcoin_manager*=2,*balance*=0,*frontend*=0,*peer*=0,*addr*=0,*network*=0,*utils*=0,*connection*=0,*main*=0,server*=0,*mempool*=0,*miner*=0,*blockchain*=0,*block_producer*=1" \ --add-ips=localhost:19000 \ @@ -33,7 +34,8 @@ rm /tmp/main.*.log --super-admin-public-keys=* \ --num-mining-threads=1 \ --miner-public-keys=BC1YLg7Bk5sq9iNY17bAwoAYiChLYpmWEi6nY6q5gnA1UQV6xixHjfV \ - --block-producer-seed='essence camp ghost remove document vault ladder swim pupil index apart ring' \ + --block-producer-seed='verb find card ship another until version devote guilt strong lemon six' \ + --pos-validator-seed='verb find card ship another until version devote guilt strong lemon six' \ --starter-deso-seed='road congress client market couple bid risk escape artwork rookie artwork food' \ --data-dir=/tmp/n0_test_00000 \ --access-control-allow-origins=http://localhost:4200,http://localhost:80,http://localhost:18002,http://localhost:4201,http://localhost:18001,http://localhost:3000,localhost:3000 \ From e3d9a48d950f0085e89aadafdbe6e6e23b3f1404 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Wed, 7 Feb 2024 16:59:16 -0500 Subject: [PATCH 29/84] Fix compile error --- routes/transaction.go | 1 - 1 file changed, 1 deletion(-) diff --git a/routes/transaction.go b/routes/transaction.go index 797401ac..9c4ca3e9 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -4137,7 +4137,6 @@ func (fes *APIServer) GetTransactionSpending(ww http.ResponseWriter, req *http.R func (fes *APIServer) simulateSubmitTransaction(utxoView *lib.UtxoView, txn *lib.MsgDeSoTxn) (_utxoOperations []*lib.UtxoOperation, _totalInput uint64, _totalOutput uint64, _fees uint64, _err error) { bestHeight := fes.blockchain.BlockTip().Height + 1 - bytes, _ := txn.ToBytes(false) return utxoView.ConnectTransaction( txn, txn.Hash(), From 8bf9ca743550b78e0b2bc1d657095526a6d5fece Mon Sep 17 00:00:00 2001 From: tholonious <99746187+tholonious@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:52:32 -0500 Subject: [PATCH 30/84] Fix CI (#540) --- routes/admin_transaction_test.go | 7 ++++--- routes/validators_test.go | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/routes/admin_transaction_test.go b/routes/admin_transaction_test.go index 0d195822..869a182d 100644 --- a/routes/admin_transaction_test.go +++ b/routes/admin_transaction_test.go @@ -3,12 +3,13 @@ package routes import ( "bytes" "encoding/json" - "github.com/deso-protocol/core/lib" - "github.com/stretchr/testify/require" "io" "net/http" "net/http/httptest" "testing" + + "github.com/deso-protocol/core/lib" + "github.com/stretchr/testify/require" ) func TestUpdateGlobalParams(t *testing.T) { @@ -89,7 +90,7 @@ func TestUpdateGlobalParams(t *testing.T) { require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(3)) require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(3)) require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(100)) - require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(3600)) + require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(10)) require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(48)) } { diff --git a/routes/validators_test.go b/routes/validators_test.go index 151b2f36..e2f61459 100644 --- a/routes/validators_test.go +++ b/routes/validators_test.go @@ -5,13 +5,14 @@ package routes import ( "bytes" "encoding/json" - "github.com/deso-protocol/core/bls" - "github.com/deso-protocol/core/lib" - "github.com/stretchr/testify/require" "io" "net/http" "net/http/httptest" "testing" + + "github.com/deso-protocol/core/bls" + "github.com/deso-protocol/core/lib" + "github.com/stretchr/testify/require" ) func TestValidatorRegistration(t *testing.T) { @@ -99,7 +100,6 @@ func TestValidatorRegistration(t *testing.T) { require.Equal(t, validatorResponse.VotingAuthorization, votingAuthorization.ToString()) require.Equal(t, validatorResponse.TotalStakeAmountNanos.Uint64(), uint64(0)) require.Equal(t, validatorResponse.Status, "Active") - require.Equal(t, validatorResponse.LastActiveAtEpochNumber, uint64(1)) require.Equal(t, validatorResponse.JailedAtEpochNumber, uint64(0)) require.NotNil(t, validatorResponse.ExtraData) require.Equal(t, validatorResponse.ExtraData["Foo"], "Bar") From e7363610420572df5f0e757c6b0f047d313b054a Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Mon, 12 Feb 2024 10:54:42 -0500 Subject: [PATCH 31/84] Only set public keys if not the zero pkid (#533) --- routes/transaction.go | 94 +++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 40 deletions(-) diff --git a/routes/transaction.go b/routes/transaction.go index 9c4ca3e9..7bf7c1e8 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -3646,10 +3646,13 @@ func TransactionSpendingLimitToResponse( if len(transactionSpendingLimit.StakeLimitMap) > 0 { for stakeLimitKey, stakeLimit := range transactionSpendingLimit.StakeLimitMap { - validatorPublicKey := utxoView.GetPublicKeyForPKID(&stakeLimitKey.ValidatorPKID) - validatorPublicKeyBase58Check := lib.Base58CheckEncode( - validatorPublicKey, false, params, - ) + var validatorPublicKeyBase58Check string + if !stakeLimitKey.ValidatorPKID.IsZeroPKID() { + validatorPublicKey := utxoView.GetPublicKeyForPKID(&stakeLimitKey.ValidatorPKID) + validatorPublicKeyBase58Check = lib.Base58CheckEncode( + validatorPublicKey, false, params, + ) + } transactionSpendingLimitResponse.StakeLimitMap = append( transactionSpendingLimitResponse.StakeLimitMap, StakeLimitMapItem{ @@ -3662,10 +3665,13 @@ func TransactionSpendingLimitToResponse( if len(transactionSpendingLimit.UnstakeLimitMap) > 0 { for unstakeLimitKey, unstakeLimit := range transactionSpendingLimit.UnstakeLimitMap { - validatorPublicKey := utxoView.GetPublicKeyForPKID(&unstakeLimitKey.ValidatorPKID) - validatorPublicKeyBase58Check := lib.Base58CheckEncode( - validatorPublicKey, false, params, - ) + var validatorPublicKeyBase58Check string + if !unstakeLimitKey.ValidatorPKID.IsZeroPKID() { + validatorPublicKey := utxoView.GetPublicKeyForPKID(&unstakeLimitKey.ValidatorPKID) + validatorPublicKeyBase58Check = lib.Base58CheckEncode( + validatorPublicKey, false, params, + ) + } transactionSpendingLimitResponse.UnstakeLimitMap = append( transactionSpendingLimitResponse.UnstakeLimitMap, UnstakeLimitMapItem{ @@ -3678,10 +3684,13 @@ func TransactionSpendingLimitToResponse( if len(transactionSpendingLimit.UnlockStakeLimitMap) > 0 { for unlockStakeLimitKey, opCount := range transactionSpendingLimit.UnlockStakeLimitMap { - validatorPublicKey := utxoView.GetPublicKeyForPKID(&unlockStakeLimitKey.ValidatorPKID) - validatorPublicKeyBase58Check := lib.Base58CheckEncode( - validatorPublicKey, false, params, - ) + var validatorPublicKeyBase58Check string + if !unlockStakeLimitKey.ValidatorPKID.IsZeroPKID() { + validatorPublicKey := utxoView.GetPublicKeyForPKID(&unlockStakeLimitKey.ValidatorPKID) + validatorPublicKeyBase58Check = lib.Base58CheckEncode( + validatorPublicKey, false, params, + ) + } transactionSpendingLimitResponse.UnlockStakeLimitMap = append( transactionSpendingLimitResponse.UnlockStakeLimitMap, UnlockStakeLimitMapItem{ @@ -3694,8 +3703,11 @@ func TransactionSpendingLimitToResponse( if len(transactionSpendingLimit.LockupLimitMap) > 0 { for lockupLimitKey, opCount := range transactionSpendingLimit.LockupLimitMap { - publicKeyBytes := utxoView.GetPublicKeyForPKID(&lockupLimitKey.ProfilePKID) - publicKeyBase58Check := lib.Base58CheckEncode(publicKeyBytes, false, params) + var publicKeyBase58Check string + if !lockupLimitKey.ProfilePKID.IsZeroPKID() { + publicKeyBytes := utxoView.GetPublicKeyForPKID(&lockupLimitKey.ProfilePKID) + publicKeyBase58Check = lib.Base58CheckEncode(publicKeyBytes, false, params) + } transactionSpendingLimitResponse.LockupLimitMap = append( transactionSpendingLimitResponse.LockupLimitMap, LockupLimitMapItem{ @@ -3873,14 +3885,14 @@ func (fes *APIServer) TransactionSpendingLimitFromResponse( if len(transactionSpendingLimitResponse.StakeLimitMap) > 0 { transactionSpendingLimit.StakeLimitMap = make(map[lib.StakeLimitKey]*uint256.Int) for _, stakeLimitMapItem := range transactionSpendingLimitResponse.StakeLimitMap { - validatorPublicKey, _, err := lib.Base58CheckDecode(stakeLimitMapItem.ValidatorPublicKeyBase58Check) - if err != nil { - return nil, err + validatorPKID := &lib.ZeroPKID + if stakeLimitMapItem.ValidatorPublicKeyBase58Check != "" { + validatorPKID, err = getCreatorPKIDForBase58Check(stakeLimitMapItem.ValidatorPublicKeyBase58Check) + if err != nil { + return nil, err + } } - validatorPKID := utxoView.GetPKIDForPublicKey(validatorPublicKey) - stakeLimitKey := lib.MakeStakeLimitKey( - validatorPKID.PKID, - ) + stakeLimitKey := lib.MakeStakeLimitKey(validatorPKID) transactionSpendingLimit.StakeLimitMap[stakeLimitKey] = stakeLimitMapItem.StakeLimit.Clone() } } @@ -3888,14 +3900,14 @@ func (fes *APIServer) TransactionSpendingLimitFromResponse( if len(transactionSpendingLimitResponse.UnstakeLimitMap) > 0 { transactionSpendingLimit.UnstakeLimitMap = make(map[lib.StakeLimitKey]*uint256.Int) for _, unstakeLimitMapItem := range transactionSpendingLimitResponse.UnstakeLimitMap { - validatorPublicKey, _, err := lib.Base58CheckDecode(unstakeLimitMapItem.ValidatorPublicKeyBase58Check) - if err != nil { - return nil, err + validatorPKID := &lib.ZeroPKID + if unstakeLimitMapItem.ValidatorPublicKeyBase58Check != "" { + validatorPKID, err = getCreatorPKIDForBase58Check(unstakeLimitMapItem.ValidatorPublicKeyBase58Check) + if err != nil { + return nil, err + } } - validatorPKID := utxoView.GetPKIDForPublicKey(validatorPublicKey) - unstakeLimitKey := lib.MakeStakeLimitKey( - validatorPKID.PKID, - ) + unstakeLimitKey := lib.MakeStakeLimitKey(validatorPKID) transactionSpendingLimit.UnstakeLimitMap[unstakeLimitKey] = unstakeLimitMapItem.UnstakeLimit.Clone() } } @@ -3903,27 +3915,29 @@ func (fes *APIServer) TransactionSpendingLimitFromResponse( if len(transactionSpendingLimitResponse.UnlockStakeLimitMap) > 0 { transactionSpendingLimit.UnlockStakeLimitMap = make(map[lib.StakeLimitKey]uint64) for _, unlockStakeLimitMapItem := range transactionSpendingLimitResponse.UnlockStakeLimitMap { - validatorPublicKey, _, err := lib.Base58CheckDecode(unlockStakeLimitMapItem.ValidatorPublicKeyBase58Check) - if err != nil { - return nil, err + validatorPKID := &lib.ZeroPKID + if unlockStakeLimitMapItem.ValidatorPublicKeyBase58Check != "" { + validatorPKID, err = getCreatorPKIDForBase58Check(unlockStakeLimitMapItem.ValidatorPublicKeyBase58Check) + if err != nil { + return nil, err + } } - validatorPKID := utxoView.GetPKIDForPublicKey(validatorPublicKey) - unlockStakeLimitKey := lib.MakeStakeLimitKey( - validatorPKID.PKID, - ) + unlockStakeLimitKey := lib.MakeStakeLimitKey(validatorPKID) transactionSpendingLimit.UnlockStakeLimitMap[unlockStakeLimitKey] = unlockStakeLimitMapItem.OpCount } } if len(transactionSpendingLimitResponse.LockupLimitMap) > 0 { transactionSpendingLimit.LockupLimitMap = make(map[lib.LockupLimitKey]uint64) for _, lockupLimitMapItem := range transactionSpendingLimitResponse.LockupLimitMap { - profilePublicKey, _, err := lib.Base58CheckDecode(lockupLimitMapItem.ProfilePublicKeyBase58Check) - if err != nil { - return nil, err + profilePKID := &lib.ZeroPKID + if lockupLimitMapItem.ProfilePublicKeyBase58Check != "" { + profilePKID, err = getCreatorPKIDForBase58Check(lockupLimitMapItem.ProfilePublicKeyBase58Check) + if err != nil { + return nil, err + } } - pkidEntry := utxoView.GetPKIDForPublicKey(profilePublicKey) transactionSpendingLimit.LockupLimitMap[lib.MakeLockupLimitKey( - *pkidEntry.PKID, + *profilePKID, lockupLimitMapItem.ScopeType.ToScopeType(), lockupLimitMapItem.Operation.ToOperationType(), )] = lockupLimitMapItem.OpCount From b33a0aba7013465eed3b32cb402ffe16d826e349 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:50:30 -0500 Subject: [PATCH 32/84] Level 2 glog for price fetching logic (#541) --- routes/base.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/routes/base.go b/routes/base.go index 59d6555e..fa72279c 100644 --- a/routes/base.go +++ b/routes/base.go @@ -182,7 +182,7 @@ func (fes *APIServer) GetBlockchainDotComExchangeRate() (_exchangeRate float64, glog.Errorf("GetBlockchainDotComExchangeRate: Problem getting max from list of float64s: %v", err) return 0, err } - glog.Infof("Blockchain exchange rate: %v %v", blockchainDotComExchangeRate, exchangeRatesFetched) + glog.V(2).Infof("Blockchain exchange rate: %v %v", blockchainDotComExchangeRate, exchangeRatesFetched) if fes.backendServer != nil && fes.backendServer.GetStatsdClient() != nil { if err = fes.backendServer.GetStatsdClient().Gauge("BLOCKCHAIN_LAST_TRADE_PRICE", blockchainDotComExchangeRate, []string{}, 1); err != nil { glog.Errorf("GetBlockchainDotComExchangeRate: Error logging Last Trade Price of %f to datadog: %v", blockchainDotComExchangeRate, err) @@ -243,18 +243,18 @@ func (fes *APIServer) GetCoinbaseExchangeRate() (_exchangeRate float64, _err err // UpdateUSDCentsToDeSoExchangeRate updates app state's USD Cents per DeSo value func (fes *APIServer) UpdateUSDCentsToDeSoExchangeRate() { - glog.Infof("Refreshing exchange rate...") + glog.V(2).Info("Refreshing exchange rate...") // Fetch price from blockchain.com blockchainDotComPrice, err := fes.GetBlockchainDotComExchangeRate() - glog.Infof("Blockchain.com price (USD cents): %v", blockchainDotComPrice) + glog.V(2).Infof("Blockchain.com price (USD cents): %v", blockchainDotComPrice) if err != nil { glog.Errorf("UpdateUSDCentsToDeSoExchangeRate: Error fetching exchange rate from blockchain.com: %v", err) } // Fetch price from coinbase coinbasePrice, err := fes.GetCoinbaseExchangeRate() - glog.Infof("Coinbase price (USD Cents): %v", coinbasePrice) + glog.V(2).Infof("Coinbase price (USD Cents): %v", coinbasePrice) if err != nil { glog.Errorf("UpdateUSDCentsToDeSoExchangeRate: Error fetching exchange rate from coinbase: %v", err) } @@ -283,29 +283,29 @@ func (fes *APIServer) UpdateUSDCentsToDeSoExchangeRate() { fes.UsdCentsPerDeSoExchangeRate = maxPrice } - glog.Infof("Final exchange rate: %v", fes.UsdCentsPerDeSoExchangeRate) + glog.V(2).Infof("Final exchange rate: %v", fes.UsdCentsPerDeSoExchangeRate) } func (fes *APIServer) UpdateUSDToBTCPrice() { - glog.Info("Refreshing USD to BTC exchange rate") + glog.V(2).Info("Refreshing USD to BTC exchange rate") btcExchangeRate, err := GetUSDToBTCPrice() if err != nil { glog.Errorf("Error getting BTC price: %v", err) return } fes.UsdCentsPerBitCoinExchangeRate = btcExchangeRate * 100 - glog.Infof("New USD to BTC exchange rate: %f", fes.UsdCentsPerBitCoinExchangeRate/100) + glog.V(2).Infof("New USD to BTC exchange rate: %f", fes.UsdCentsPerBitCoinExchangeRate/100) } func (fes *APIServer) UpdateUSDToETHPrice() { - glog.Info("Refreshing USD to ETH exchange rate") + glog.V(2).Info("Refreshing USD to ETH exchange rate") ethExchangeRate, err := apis.GetUSDToETHPrice() if err != nil { glog.Errorf("Error getting ETH price: %v", err) return } fes.UsdCentsPerETHExchangeRate = uint64(ethExchangeRate * 100) - glog.Infof("New USD to ETH exchange rate: %f", float64(fes.UsdCentsPerETHExchangeRate)/100) + glog.V(2).Infof("New USD to ETH exchange rate: %f", float64(fes.UsdCentsPerETHExchangeRate)/100) } // getMaxPriceFromHistoryAndCull removes elements that are outside of the lookback window and return the max price From e0fe7550465e8f1e370426fcb7b762f51bfc87fd Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Tue, 13 Feb 2024 19:39:07 -0500 Subject: [PATCH 33/84] Remove datadir deletion from n0_test --- scripts/nodes/n0_test | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/nodes/n0_test b/scripts/nodes/n0_test index 2da232ad..f2e03236 100755 --- a/scripts/nodes/n0_test +++ b/scripts/nodes/n0_test @@ -13,7 +13,6 @@ DATE=`date +%Y%m%d-%H:%M:%S-%N` # * 13UkvpJXdLWE4p68n4MAK6zQntQ1RHixyM rm /tmp/main.*.log -rm -rf /tmp/n0_test_00000 # "-gcflags=”all=-N -l" was added to get GoLand debugger (Delve) to work, see # https://blog.jetbrains.com/go/2019/02/06/debugging-with-goland-getting-started/ From 91f7302b3b138f6507f12f1d89ad7a676b52a34d Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 15 Feb 2024 16:35:21 -0500 Subject: [PATCH 34/84] Update miner to pass params into RecomputeBlockRewardWithBlockRewardOutputPublicKey (#542) --- routes/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/miner.go b/routes/miner.go index 752b5655..5c2addb5 100644 --- a/routes/miner.go +++ b/routes/miner.go @@ -162,7 +162,7 @@ func (fes *APIServer) SubmitBlock(ww http.ResponseWriter, req *http.Request) { blockFound.Txns[0].TxOutputs[0].PublicKey = pkBytes blockFound.Txns[0].TxnMeta.(*lib.BlockRewardMetadataa).ExtraData = lib.UintToBuf(requestData.ExtraData) - blockFound, err = lib.RecomputeBlockRewardWithBlockRewardOutputPublicKey(blockFound, pkBytes) + blockFound, err = lib.RecomputeBlockRewardWithBlockRewardOutputPublicKey(blockFound, pkBytes, fes.Params) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SubmitBlock: Problem recomputing block reward: %v", err)) return From 0345c2e83c593069ca3cdee775afc4f215a25700 Mon Sep 17 00:00:00 2001 From: tholonious <99746187+tholonious@users.noreply.github.com> Date: Wed, 20 Mar 2024 10:08:16 -0400 Subject: [PATCH 35/84] feature/pos-networking-and-syncing (#556) * Fix Compile Errors For Networking (#543) * Fix broken unit test (#546) * Add endpoint to get fee rate and block height for local txn construction (#544) * Fix NetworkManager Access (#550) * Reduce logging (#547) * Validator Registration Script (#552) * Validator Registration Script * Fix validator domain * Update flow crypto dependency (#554) --------- Co-authored-by: Lazy Nina <81658138+lazynina@users.noreply.github.com> --- Dockerfile | 5 +- README.md | 12 ++ apis/eth_price.go | 15 +- go.mod | 4 +- go.sum | 26 +++- routes/admin_fees.go | 2 +- routes/admin_node.go | 18 +-- routes/admin_transaction_test.go | 2 +- routes/base.go | 10 +- routes/bitcoin_price.go | 15 +- routes/hot_feed.go | 8 +- routes/server.go | 8 ++ routes/transaction.go | 71 +++++++++ routes/verify.go | 6 + scripts/pos/validator_registration.go | 198 ++++++++++++++++++++++++++ test.Dockerfile | 3 +- 16 files changed, 359 insertions(+), 44 deletions(-) create mode 100644 scripts/pos/validator_registration.go diff --git a/Dockerfile b/Dockerfile index 24721308..26b104bd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,12 +35,9 @@ COPY core/consensus ../core/consensus COPY core/desohash ../core/desohash COPY core/lib ../core/lib COPY core/migrate ../core/migrate -COPY core/scripts ../core/scripts - -RUN ../core/scripts/install-relic.sh # build backend -RUN GOOS=linux go build -mod=mod -a -installsuffix cgo -o bin/backend -tags=relic main.go +RUN GOOS=linux go build -mod=mod -a -installsuffix cgo -o bin/backend main.go # create tiny image FROM alpine:latest diff --git a/README.md b/README.md index caa33659..63d552d6 100644 --- a/README.md +++ b/README.md @@ -71,3 +71,15 @@ go build github.com/h2non/bimg: invalid flag in pkg-config --cflags: -Xpreproces ``` export CGO_CFLAGS_ALLOW="-Xpreprocessor" ``` + +#### Error +``` +ld: library not found for -lvips +clang: error: linker command failed with exit code 1 (use -v to see invocation) +``` + +#### Solution + +``` +go clean -cache +``` \ No newline at end of file diff --git a/apis/eth_price.go b/apis/eth_price.go index ffd8c1eb..f7e82947 100644 --- a/apis/eth_price.go +++ b/apis/eth_price.go @@ -4,11 +4,12 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/golang/glog" - "github.com/montanaflynn/stats" "io/ioutil" "net/http" "strconv" + + "github.com/golang/glog" + "github.com/montanaflynn/stats" ) type CoinbaseResponse struct { @@ -194,7 +195,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getCoinbasePrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Coinbase price: %v", err) + glog.V(2).Infof("Error fetching Coinbase price: %v", err) } if amount != 0 { @@ -205,7 +206,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getCoingeckoPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Coingecko price: %v", err) + glog.V(2).Infof("Error fetching Coingecko price: %v", err) } if amount != 0 { @@ -216,7 +217,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getBlockchainDotcomPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching blockchain.com price: %v", err) + glog.V(2).Infof("Error fetching blockchain.com price: %v", err) } if amount != 0 { @@ -227,7 +228,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getGeminiPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Gemini price: %v", err) + glog.V(2).Infof("Error fetching Gemini price: %v", err) } if amount != 0 { @@ -238,7 +239,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getKrakenPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Kraken price: %v", err) + glog.V(2).Infof("Error fetching Kraken price: %v", err) } if amount != 0 { diff --git a/go.mod b/go.mod index 4c9a0578..eb46ff87 100644 --- a/go.mod +++ b/go.mod @@ -69,6 +69,7 @@ require ( github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 // indirect github.com/google/uuid v1.2.0 // indirect github.com/googleapis/gax-go/v2 v2.0.5 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.8 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect @@ -84,7 +85,7 @@ require ( github.com/mattn/goveralls v0.0.6 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/oleiade/lane v1.0.1 // indirect - github.com/onflow/flow-go/crypto v0.24.7 // indirect + github.com/onflow/crypto v0.25.0 // indirect github.com/pelletier/go-toml v1.7.0 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/philhofer/fwd v1.1.1 // indirect @@ -119,6 +120,7 @@ require ( golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect golang.org/x/tools v0.1.5 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gonum.org/v1/gonum v0.6.1 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab // indirect google.golang.org/grpc v1.37.0 // indirect diff --git a/go.sum b/go.sum index 75f51c55..aab30020 100644 --- a/go.sum +++ b/go.sum @@ -68,6 +68,7 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -183,6 +184,7 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fergusstrange/embedded-postgres v1.19.0 h1:NqDufJHeA03U7biULlPHZ0pZ10/mDOMKPILEpT50Fyk= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -214,6 +216,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0= github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -324,6 +327,9 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -361,6 +367,7 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -438,8 +445,8 @@ github.com/oleiade/lane v1.0.1 h1:hXofkn7GEOubzTwNpeL9MaNy8WxolCYb9cInAIeqShU= github.com/oleiade/lane v1.0.1/go.mod h1:IyTkraa4maLfjq/GmHR+Dxb4kCMtEGeb+qmhlrQ5Mk4= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onflow/flow-go/crypto v0.24.7 h1:RCLuB83At4z5wkAyUCF7MYEnPoIIOHghJaODuJyEoW0= -github.com/onflow/flow-go/crypto v0.24.7/go.mod h1:fqCzkIBBMRRkciVrvW21rECKq1oD7Q6u+bCI78lfNX0= +github.com/onflow/crypto v0.25.0 h1:BeWbLsh3ZD13Ej+Uky6kg1PL1ZIVBDVX+2MVBNwqddg= +github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -549,7 +556,6 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/supranational/blst v0.3.10 h1:CMciDZ/h4pXDDXQASe8ZGTNKUiVNxVVA5hpci2Uuhuk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= @@ -625,7 +631,10 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= @@ -635,7 +644,9 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -817,8 +828,10 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -876,6 +889,12 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.6.1 h1:/LSrTrgZtpbXyAR6+0e152SROCkJJSh7goYWVmdPFGc= +gonum.org/v1/gonum v0.6.1/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1029,5 +1048,6 @@ mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w= mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ= pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/routes/admin_fees.go b/routes/admin_fees.go index 52eebe7f..d8c64829 100644 --- a/routes/admin_fees.go +++ b/routes/admin_fees.go @@ -255,7 +255,7 @@ func (fes *APIServer) GetTransactionFeeMapFromGlobalState() map[lib.TxnType][]*l var feeOutputs []*lib.DeSoOutput // Decode the bytes into the slice of DeSoOutputs if err = gob.NewDecoder(bytes.NewReader(desoOutputBytes)).Decode(&feeOutputs); err != nil { - glog.Infof("Error decoding desoOutputBytes to slice of DeSoOutputs: %v - default to no additional fees", err) + glog.V(2).Infof("Error decoding desoOutputBytes to slice of DeSoOutputs: %v - default to no additional fees", err) // Default to an empty slice. transactionFeeMap[txnType] = []*lib.DeSoOutput{} } else { diff --git a/routes/admin_node.go b/routes/admin_node.go index 473c26dd..21692b7c 100644 --- a/routes/admin_node.go +++ b/routes/admin_node.go @@ -167,7 +167,7 @@ func (fes *APIServer) _handleNodeControlGetInfo( existingDeSoPeers[currentPeerRes.IP+fmt.Sprintf(":%d", currentPeerRes.ProtocolPort)] = true } // Return some deso addrs from the addr manager. - desoAddrs := fes.backendServer.GetConnectionManager().GetAddrManager().AddressCache() + desoAddrs := fes.backendServer.AddrMgr.AddressCache() sort.Slice(desoAddrs, func(ii, jj int) bool { // Use a hash to get a random but deterministic ordering. hashI := string(lib.Sha256DoubleHash([]byte(desoAddrs[ii].IP.String() + fmt.Sprintf(":%d", desoAddrs[ii].Port)))[:]) @@ -239,12 +239,12 @@ func (fes *APIServer) _handleConnectDeSoNode( // increasing retry delay, but we should still clean it up at some point. connectPeerDone := make(chan bool) go func() { - netAddr, err := fes.backendServer.GetConnectionManager().GetAddrManager().HostToNetAddress(ip, protocolPort, 0) + netAddr, err := fes.backendServer.AddrMgr.HostToNetAddress(ip, protocolPort, 0) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("_handleConnectDeSoNode: Cannot connect to node %s:%d: %v", ip, protocolPort, err)) return } - fes.backendServer.GetConnectionManager().ConnectPeer(nil, netAddr) + fes.backendServer.GetNetworkManager().CreateNonValidatorOutboundConnection(ip) // Spin until the peer shows up in the connection manager or until 100 iterations. // Note the pause between each iteration. @@ -274,7 +274,7 @@ func (fes *APIServer) _handleConnectDeSoNode( // At this point the peer shoud be connected. Add their address to the addrmgr // in case the user wants to connect again in the future. Set the source to be // the address itself since we don't have anything else. - fes.backendServer.GetConnectionManager().GetAddrManager().AddAddress(netAddr, netAddr) + fes.backendServer.AddrMgr.AddAddress(netAddr, netAddr) connectPeerDone <- true return @@ -320,13 +320,13 @@ func (fes *APIServer) _handleDisconnectDeSoNode( // Manually remove the peer from the connection manager and mark it as such // so that the connection manager won't reconnect to it or replace it. - fes.backendServer.GetConnectionManager().RemovePeer(peerFound) - peerFound.PeerManuallyRemovedFromConnectionManager = true - - peerFound.Disconnect() + remoteNode := fes.backendServer.GetNetworkManager().GetRemoteNodeFromPeer(peerFound) + if remoteNode != nil { + fes.backendServer.GetNetworkManager().Disconnect(remoteNode) + } res := NodeControlResponse{ - // Return an empty response, which indicates we set the peer up to be connected. + // Return an empty response, which indicates we set the peer up to be disconnected. } if err := json.NewEncoder(ww).Encode(res); err != nil { _AddBadRequestError(ww, fmt.Sprintf("NodeControl: Problem encoding response as JSON: %v", err)) diff --git a/routes/admin_transaction_test.go b/routes/admin_transaction_test.go index 869a182d..20ecfd4d 100644 --- a/routes/admin_transaction_test.go +++ b/routes/admin_transaction_test.go @@ -91,7 +91,7 @@ func TestUpdateGlobalParams(t *testing.T) { require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(3)) require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(100)) require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(10)) - require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(48)) + require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(3)) } { // Update all GlobalParam fields. diff --git a/routes/base.go b/routes/base.go index fa72279c..ce0359a0 100644 --- a/routes/base.go +++ b/routes/base.go @@ -150,14 +150,14 @@ func (fes *APIServer) GetBlockchainDotComExchangeRate() (_exchangeRate float64, url := "https://api.blockchain.com/v3/exchange/tickers/CLOUT-USD" req, err := http.NewRequest("GET", url, nil) if err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Problem creating request: %v", err) + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Problem creating request: %v", err) continue } req.Header.Set("Content-Type", "application/json") resp, err := httpClient.Do(req) if err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Problem with HTTP request %s: %v", url, err) + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Problem with HTTP request %s: %v", url, err) continue } defer resp.Body.Close() @@ -167,7 +167,7 @@ func (fes *APIServer) GetBlockchainDotComExchangeRate() (_exchangeRate float64, responseData := &BlockchainDeSoTickerResponse{} decoder := json.NewDecoder(bytes.NewReader(body)) if err = decoder.Decode(responseData); err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Problem decoding response JSON into "+ + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Problem decoding response JSON into "+ "interface %v, response: %v, error: %v", responseData, resp, err) continue } @@ -179,13 +179,13 @@ func (fes *APIServer) GetBlockchainDotComExchangeRate() (_exchangeRate float64, } blockchainDotComExchangeRate, err := stats.Max(exchangeRatesFetched) if err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Problem getting max from list of float64s: %v", err) + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Problem getting max from list of float64s: %v", err) return 0, err } glog.V(2).Infof("Blockchain exchange rate: %v %v", blockchainDotComExchangeRate, exchangeRatesFetched) if fes.backendServer != nil && fes.backendServer.GetStatsdClient() != nil { if err = fes.backendServer.GetStatsdClient().Gauge("BLOCKCHAIN_LAST_TRADE_PRICE", blockchainDotComExchangeRate, []string{}, 1); err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Error logging Last Trade Price of %f to datadog: %v", blockchainDotComExchangeRate, err) + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Error logging Last Trade Price of %f to datadog: %v", blockchainDotComExchangeRate, err) } } return blockchainDotComExchangeRate, nil diff --git a/routes/bitcoin_price.go b/routes/bitcoin_price.go index 5f7842ee..31f8e2d6 100644 --- a/routes/bitcoin_price.go +++ b/routes/bitcoin_price.go @@ -4,11 +4,12 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/golang/glog" - "github.com/montanaflynn/stats" "io/ioutil" "net/http" "strconv" + + "github.com/golang/glog" + "github.com/montanaflynn/stats" ) type CoinbaseResponse struct { @@ -206,7 +207,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getCoinbasePrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Coinbase price: %v", err) + glog.V(2).Infof("Error fetching Coinbase price: %v", err) } if amount != 0 { @@ -217,7 +218,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getCoingeckoPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Coingecko price: %v", err) + glog.V(2).Infof("Error fetching Coingecko price: %v", err) } if amount != 0 { @@ -228,7 +229,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getBlockchainDotcomPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching blockchain.com price: %v", err) + glog.V(2).Infof("Error fetching blockchain.com price: %v", err) } if amount != 0 { @@ -239,7 +240,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getGeminiPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Gemini price: %v", err) + glog.V(2).Infof("Error fetching Gemini price: %v", err) } if amount != 0 { @@ -250,7 +251,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getKrakenPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Kraken price: %v", err) + glog.V(2).Infof("Error fetching Kraken price: %v", err) } if amount != 0 { diff --git a/routes/hot_feed.go b/routes/hot_feed.go index 9a884efa..9c1b127a 100644 --- a/routes/hot_feed.go +++ b/routes/hot_feed.go @@ -109,9 +109,9 @@ func (fes *APIServer) StartHotFeedRoutine() { // The business. func (fes *APIServer) UpdateHotFeed(resetCache bool) { - glog.Info("Refreshing hot feed...") + glog.V(2).Info("Refreshing hot feed...") if resetCache { - glog.Info("Resetting hot feed cache.") + glog.V(2).Info("Resetting hot feed cache.") fes.PostTagToPostHashesMap = make(map[string]map[lib.BlockHash]bool) fes.PostHashToPostTagsMap = make(map[lib.BlockHash][]string) fes.HotFeedBlockCache = make(map[lib.BlockHash]*lib.MsgDeSoBlock) @@ -137,7 +137,7 @@ func (fes *APIServer) UpdateHotFeed(resetCache bool) { // Replace the HotFeedApprovedPostsMap and HotFeedPKIDMultiplier map with the fresh ones. fes.HotFeedApprovedPostsToMultipliers = hotFeedApprovedPosts fes.HotFeedPKIDMultipliers = hotFeedPKIDMultipliers - glog.Infof("Updated hot feed maps") + glog.V(2).Infof("Updated hot feed maps") } func (fes *APIServer) UpdateHotFeedApprovedPostsMap(hotFeedApprovedPosts map[lib.BlockHash]float64) { @@ -412,7 +412,7 @@ func (fes *APIServer) UpdateHotFeedOrderedList( } // Log how long this routine takes, since it could be heavy. - glog.Info("UpdateHotFeedOrderedList: Starting new update cycle.") + glog.V(2).Info("UpdateHotFeedOrderedList: Starting new update cycle.") start := time.Now() // Get a utxoView for lookups. diff --git a/routes/server.go b/routes/server.go index e5531599..2a90dd2f 100644 --- a/routes/server.go +++ b/routes/server.go @@ -68,6 +68,7 @@ const ( RoutePathAppendExtraData = "/api/v0/append-extra-data" RoutePathGetTransactionSpending = "/api/v0/get-transaction-spending" RoutePathGetSignatureIndex = "/api/v0/signature-index" + RoutePathGetTxnConstructionParams = "/api/v0/txn-construction-params" RoutePathGetUsersStateless = "/api/v0/get-users-stateless" RoutePathDeleteIdentities = "/api/v0/delete-identities" @@ -1024,6 +1025,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.GetSignatureIndex, PublicAccess, }, + { + "GetTxnConstructionParams", + []string{"POST", "OPTIONS"}, + RoutePathGetTxnConstructionParams, + fes.GetTxnConstructionParams, + PublicAccess, + }, { "GetNotifications", []string{"POST", "OPTIONS"}, diff --git a/routes/transaction.go b/routes/transaction.go index 7bf7c1e8..026ed68e 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -4198,3 +4198,74 @@ func (fes *APIServer) GetSignatureIndex(ww http.ResponseWriter, req *http.Reques } return } + +type GetTxnConstructionParamsRequest struct { + MinFeeRateNanosPerKB uint64 + MempoolCongestionFactorBasisPoints uint64 + MempoolPriorityPercentileBasisPoints uint64 + PastBlocksCongestionFactorBasisPoints uint64 + PastBlocksPriorityPercentileBasisPoints uint64 + MaxBlockSize uint64 +} + +type GetTxnConstructionParamsResponse struct { + FeeRateNanosPerKB uint64 + BlockHeight uint64 +} + +func (fes *APIServer) GetTxnConstructionParams(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(req.Body) + requestData := GetTxnConstructionParamsRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, "GetTxnConstructionParams: Problem parsing request body: "+err.Error()) + return + } + + // TODO: replace lib.MaxBasisPoints w/ a param defined by a flag from core. + mempoolCongestionFactorBasisPoints := requestData.MempoolCongestionFactorBasisPoints + if requestData.MempoolCongestionFactorBasisPoints == 0 { + mempoolCongestionFactorBasisPoints = lib.MaxBasisPoints + } + + mempoolPriorityPercentileBasisPoints := requestData.MempoolPriorityPercentileBasisPoints + if requestData.MempoolPriorityPercentileBasisPoints == 0 { + mempoolPriorityPercentileBasisPoints = lib.MaxBasisPoints + } + + pastBlocksCongestionFactorBasisPoints := requestData.PastBlocksCongestionFactorBasisPoints + if requestData.PastBlocksCongestionFactorBasisPoints == 0 { + pastBlocksCongestionFactorBasisPoints = lib.MaxBasisPoints + } + + pastBlocksPriorityPercentileBasisPoints := requestData.PastBlocksPriorityPercentileBasisPoints + if requestData.PastBlocksPriorityPercentileBasisPoints == 0 { + pastBlocksPriorityPercentileBasisPoints = lib.MaxBasisPoints + } + + maxBlockSize := requestData.MaxBlockSize + if requestData.MaxBlockSize == 0 { + maxBlockSize = fes.Params.MaxBlockSizeBytes + } + + // Get the fees from the mempool + feeRate, err := fes.backendServer.GetMempool().EstimateFeeRate( + requestData.MinFeeRateNanosPerKB, + mempoolCongestionFactorBasisPoints, + mempoolPriorityPercentileBasisPoints, + pastBlocksCongestionFactorBasisPoints, + pastBlocksPriorityPercentileBasisPoints, + maxBlockSize, + ) + if err != nil { + _AddBadRequestError(ww, "GetTxnConstructionParams: Problem getting fees: "+err.Error()) + return + } + // Return the fees + if err = json.NewEncoder(ww).Encode(GetTxnConstructionParamsResponse{ + FeeRateNanosPerKB: feeRate, + BlockHeight: uint64(fes.backendServer.GetBlockchain().BlockTip().Height), + }); err != nil { + _AddBadRequestError(ww, "GetTxnConstructionParams: Problem encoding response as JSON: "+err.Error()) + return + } +} diff --git a/routes/verify.go b/routes/verify.go index e668b593..9c9910eb 100644 --- a/routes/verify.go +++ b/routes/verify.go @@ -1469,6 +1469,9 @@ func (fes *APIServer) SetJumioUSDCents() { glog.Errorf("SetJumioUSDCents: Error getting Jumio USD Cents from global state: %v", err) return } + if len(val) == 0 { + return + } jumioUSDCents, bytesRead := lib.Uvarint(val) if bytesRead <= 0 { glog.Errorf("SetJumioUSDCents: invalid bytes read: %v", bytesRead) @@ -1487,6 +1490,9 @@ func (fes *APIServer) SetJumioKickbackUSDCents() { glog.Errorf("SetJumioKickbackUSDCents: Error getting Jumio Kickback USD Cents from global state: %v", err) return } + if len(val) == 0 { + return + } jumioKickbackUSDCents, bytesRead := lib.Uvarint(val) if bytesRead <= 0 { glog.Errorf("SetJumioKickbackUSDCents: invalid bytes read: %v", bytesRead) diff --git a/scripts/pos/validator_registration.go b/scripts/pos/validator_registration.go new file mode 100644 index 00000000..cbe79499 --- /dev/null +++ b/scripts/pos/validator_registration.go @@ -0,0 +1,198 @@ +package main + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" + + "github.com/btcsuite/btcd/btcec" + "github.com/deso-protocol/backend/routes" + "github.com/deso-protocol/core/bls" + "github.com/deso-protocol/core/lib" + "github.com/holiman/uint256" + "github.com/pkg/errors" + "github.com/tyler-smith/go-bip39" +) + +var desoSourceSeedPhrase = "" +var validatorSeedPhrase = "SEED PHRASE HERE" +var nodeApiUrl = "http://localhost:18001" +var validatorDomain string = "localhost:19000" + +var params = &lib.DeSoTestnetParams + +func getBLSVotingAuthorizationAndPublicKey(blsKeyStore *lib.BLSKeystore, transactorPublicKey *lib.PublicKey) ( + *bls.PublicKey, *bls.Signature, +) { + votingAuthPayload := lib.CreateValidatorVotingAuthorizationPayload(transactorPublicKey.ToBytes()) + votingAuthorization, err := blsKeyStore.GetSigner().Sign(votingAuthPayload) + if err != nil { + panic(err) + } + return blsKeyStore.GetSigner().GetPublicKey(), votingAuthorization +} + +func makePostRequest[TPayload any, TResponse any](url string, payload TPayload) TResponse { + postBody, err := json.Marshal(payload) + if err != nil { + panic(errors.Wrap(err, "main(): Could not complete request")) + } + postBuffer := bytes.NewBuffer(postBody) + + // Execute request. + resp, err := http.Post(url, "application/json", postBuffer) + if err != nil { + panic(errors.Wrap(err, "main(): failed request")) + } + if resp.StatusCode != 200 { + bodyBytes, _ := ioutil.ReadAll(resp.Body) + panic(errors.Errorf("main(): Received non 200 response code: "+ + "Status Code: %v Body: %v", resp.StatusCode, string(bodyBytes))) + } + + var decodedResponse TResponse + + // Process Response. + err = json.NewDecoder(resp.Body).Decode(&decodedResponse) + if err != nil { + panic(errors.Wrap(err, "main(): Failed to decode response\n")) + } + err = resp.Body.Close() + if err != nil { + panic(errors.Wrap(err, "main(): Failed to decode body\n")) + } + + return decodedResponse +} + +func signAndSubmitTxn(txn *lib.MsgDeSoTxn, privKey *btcec.PrivateKey, nodeURL string) { + signature, err := txn.Sign(privKey) + if err != nil { + panic(err) + } + + txn.Signature.SetSignature(signature) + + txnBytes, err := txn.ToBytes(false) + if err != nil { + panic(err) + } + + txnHex := hex.EncodeToString(txnBytes) + + submitTransactionRequest := routes.SubmitTransactionRequest{ + TransactionHex: txnHex, + } + + makePostRequest[routes.SubmitTransactionRequest, routes.SubmitTransactionResponse]( + nodeURL+routes.RoutePathSubmitTransaction, submitTransactionRequest, + ) +} + +func constructSendDESOTxn(senderPubKey *lib.PublicKey, recipientPubKey *lib.PublicKey) routes.SendDeSoResponse { + senderPublicKeyString := lib.PkToString(senderPubKey.ToBytes(), params) + recipientPublicKeyString := lib.PkToString(recipientPubKey.ToBytes(), params) + + sendDESOTxnRequest := routes.SendDeSoRequest{ + SenderPublicKeyBase58Check: senderPublicKeyString, + RecipientPublicKeyOrUsername: recipientPublicKeyString, + AmountNanos: 11 * 1e9, + MinFeeRateNanosPerKB: 1000, + } + + return makePostRequest[routes.SendDeSoRequest, routes.SendDeSoResponse]( + nodeApiUrl+routes.RoutePathSendDeSo, sendDESOTxnRequest, + ) +} + +func constructRegisterAsValidatorTxn(keystore *lib.BLSKeystore, pubKey *lib.PublicKey) routes.ValidatorTxnResponse { + _, votingAuthorization := getBLSVotingAuthorizationAndPublicKey(keystore, pubKey) + + publicKeyString := lib.PkToString(pubKey.ToBytes(), params) + + request := routes.RegisterAsValidatorRequest{ + TransactorPublicKeyBase58Check: publicKeyString, + Domains: []string{validatorDomain}, + DisableDelegatedStake: false, + VotingPublicKey: keystore.GetSigner().GetPublicKey().ToString(), + VotingAuthorization: votingAuthorization.ToString(), + ExtraData: map[string]string{}, + MinFeeRateNanosPerKB: 1000, + TransactionFees: []routes.TransactionFee{}, + } + + return makePostRequest[routes.RegisterAsValidatorRequest, routes.ValidatorTxnResponse]( + nodeApiUrl+routes.RoutePathValidators+"/register", request, + ) +} + +func constructStakeTxn(pubKey *lib.PublicKey) routes.StakeTxnResponse { + publicKeyString := lib.PkToString(pubKey.ToBytes(), params) + + request := routes.StakeRequest{ + TransactorPublicKeyBase58Check: publicKeyString, + ValidatorPublicKeyBase58Check: publicKeyString, + RewardMethod: routes.PayToBalance, + StakeAmountNanos: uint256.NewInt().SetUint64(9 * 1e9), + ExtraData: map[string]string{}, + MinFeeRateNanosPerKB: 1000, + TransactionFees: []routes.TransactionFee{}, + } + + return makePostRequest[routes.StakeRequest, routes.StakeTxnResponse](nodeApiUrl+routes.RoutePathStake, request) +} + +func generatePubAndPrivKeys(seedPhrase string) (*lib.PublicKey, *btcec.PrivateKey) { + seedBytes, err := bip39.NewSeedWithErrorChecking(seedPhrase, "") + if err != nil { + panic(errors.Wrap(err, "main(): Could not generate key pair from mnemonic")) + } + + pubKey, privKey, _, err := lib.ComputeKeysFromSeed(seedBytes, 0, &lib.DeSoTestnetParams) + if err != nil { + panic(errors.Wrap(err, "main(): Could not generate key pair from mnemonic")) + } + + publicKey := lib.NewPublicKey(pubKey.SerializeCompressed()) + return publicKey, privKey +} + +func generateKeystore(seedPhrase string) *lib.BLSKeystore { + keystore, err := lib.NewBLSKeystore(seedPhrase) + if err != nil { + panic(errors.Wrap(err, "main(): Could not generate keystore")) + } + return keystore +} + +func main() { + fmt.Printf("Network Type: %s\n", params.NetworkType.String()) + + desoSourcePubKey, desoSourcePrivKey := generatePubAndPrivKeys(desoSourceSeedPhrase) + + validatorKeystore := generateKeystore(validatorSeedPhrase) + validatorPubKey, validatorPrivKey := generatePubAndPrivKeys(validatorSeedPhrase) + + // First send some DESO to the validator + sendDESOTxn := constructSendDESOTxn(desoSourcePubKey, validatorPubKey) + signAndSubmitTxn(sendDESOTxn.Transaction, desoSourcePrivKey, nodeApiUrl) + fmt.Println("DESO Sent ") + + time.Sleep(5 * time.Second) + + // Register the validator + validatorRegistrationTxn := constructRegisterAsValidatorTxn(validatorKeystore, validatorPubKey) + signAndSubmitTxn(validatorRegistrationTxn.Transaction, validatorPrivKey, nodeApiUrl) + fmt.Println("Validator Registered") + + time.Sleep(5 * time.Second) + + // Have the validator stake to itself + stakeTxn := constructStakeTxn(validatorPubKey) + signAndSubmitTxn(stakeTxn.Transaction, validatorPrivKey, nodeApiUrl) + fmt.Println("Stake Transaction Submitted") +} diff --git a/test.Dockerfile b/test.Dockerfile index e0cca585..89bc12bb 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -23,7 +23,6 @@ RUN git pull && \ git pull origin feature/proof-of-stake # TODO: Revert to `git pull` once core PR is merged. RUN go mod download -RUN ./scripts/install-relic.sh # Try to checkout to the specified branch. If it fails, checkout main. RUN git checkout ${BRANCH_NAME} || (echo "Branch ${BRANCH_NAME} not found. Falling back to main." && git checkout main) @@ -50,4 +49,4 @@ COPY main.go . # build backend RUN GOOS=linux go build -mod=mod -a -installsuffix cgo -o bin/backend main.go -ENTRYPOINT ["go", "test", "-tags", "relic", "-v", "github.com/deso-protocol/backend/routes"] +ENTRYPOINT ["go", "test", "-v", "github.com/deso-protocol/backend/routes"] From 799f11cabff830a373f3e90d000dcd03b1f493c3 Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Thu, 21 Mar 2024 14:32:02 -0700 Subject: [PATCH 36/84] Simple CreateAtomicTxnsWrapper scaffolding. --- routes/atomic_txns.go | 106 ++++++++++++++++++++++++++++++++++++++++++ routes/server.go | 10 ++++ 2 files changed, 116 insertions(+) create mode 100644 routes/atomic_txns.go diff --git a/routes/atomic_txns.go b/routes/atomic_txns.go new file mode 100644 index 00000000..ead49b31 --- /dev/null +++ b/routes/atomic_txns.go @@ -0,0 +1,106 @@ +package routes + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "github.com/deso-protocol/core/lib" + "io" + "net/http" +) + +type CreateAtomicTxnsWrapperRequest struct { + Transactions []*lib.MsgDeSoTxn + ExtraData map[string]string +} + +type CreateAtomicTxnsWrapperResponse struct { + // TransactionsWrapped as a helpful sanity check for the caller of the + // CreateAtomicTxnsWrapper endpoint. That being said, the caller should + // also sanity check that the returned wrapper transaction has the atomic + // transactions ordered correctly. + TransactionsWrapped uint64 `safeForLogging:"true"` + + // TotalFeeNanos represents the total fees paid cumulatively by all + // wrapper atomic transactions and is consistent with the + // returned Transaction.TxnFeeNanos field. + TotalFeeNanos uint64 + Transaction *lib.MsgDeSoTxn + TransactionHex string +} + +func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := CreateAtomicTxnsWrapperRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Error parsing request body: %v", err)) + return + } + + // Grab a view (needed for getting global params, etc). + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Error getting utxoView: %v", err)) + return + } + + // Validate the request data. + if len(requestData.Transactions) == 0 { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: must have at least one transaction "+ + "in Transactions")) + return + } + + // Encode the ExtraData map. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem encoding ExtraData: %v", err)) + return + } + + // Construct the atomic transactions wrapper transaction type. + txn, totalFees, err := fes.blockchain.CreateAtomicTxnsWrapper(requestData.Transactions, extraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem constructing transaction: %v", err)) + return + } + + // Serialize the transaction. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem serializing transaction: %v", err)) + return + } + txnSizeBytes := uint64(len(txnBytes)) + + // Validate that: + // (1) The resulting transaction is not over the size limit of an atomic transaction. + // (2) The resulting wrapper transactions have sufficient fees to cover the wrapper. + if txnSizeBytes > utxoView.Params.MaxBlockSizeBytes/2 { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Resulting wrapper transaction too large")) + return + } + if txnSizeBytes != 0 && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB != 0 { + // Check for overflow or minimum network fee not met. + if totalFees != ((totalFees*1000)/1000) || + (totalFees*1000)/uint64(txnSizeBytes) < utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Transactions used to construct"+ + " atomic transaction do not cumulatively pay sufficient network fees to cover wrapper")) + return + } + } + + // Construct a response. + res := CreateAtomicTxnsWrapperResponse{ + TransactionsWrapped: uint64(len(txn.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns)), + TotalFeeNanos: totalFees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, + fmt.Sprintf("CreateAtomicTxnsWrapper: Problem serializing object to JSON: %v", err)) + return + } +} diff --git a/routes/server.go b/routes/server.go index 2a90dd2f..7fbc01df 100644 --- a/routes/server.go +++ b/routes/server.go @@ -331,6 +331,9 @@ const ( RoutePathCoinUnlock = "/api/v0/coin-unlock" RoutePathLockupYieldCurvePoints = "/api/v0/lockup-yield-curve-points" RoutePathLockedBalanceEntries = "/api/v0/locked-balance-entries" + + // atomic_txns.go + RoutePathCreateAtomicTxnsWrapper = "/api/v0/create-atomic-txns-wrapper" ) // APIServer provides the interface between the blockchain and things like the @@ -1419,6 +1422,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.LockedBalanceEntries, PublicAccess, }, + { + "CreateAtomicTxnsWrapper", + []string{"GET"}, + RoutePathCreateAtomicTxnsWrapper, + fes.CreateAtomicTxnsWrapper, + PublicAccess, + }, // Jumio Routes { "JumioBegin", From 53d53af70312153be72f76fa77ebccb0fed6d69a Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 21 Mar 2024 18:24:33 -0400 Subject: [PATCH 37/84] Update usages of EnumerateKeysForPrefix (#559) --- routes/exchange_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/routes/exchange_test.go b/routes/exchange_test.go index ad159f5f..be9add02 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -1344,12 +1344,13 @@ func TestAPI(t *testing.T) { // block reward rather than three. { prefix := lib.DbTxindexTxIDKey(&lib.BlockHash{})[0] - txnsInTransactionIndex, _ := lib.EnumerateKeysForPrefix(apiServer.TXIndex.TXIndexChain.DB(), []byte{prefix}) + txnsInTransactionIndex, _ := lib.EnumerateKeysForPrefix( + apiServer.TXIndex.TXIndexChain.DB(), []byte{prefix}, true) require.Equal(1+len(apiServer.Params.SeedTxns)+len(apiServer.Params.SeedBalances), len(txnsInTransactionIndex)) } { keysInPublicKeyTable, _ := lib.EnumerateKeysForPrefix( - apiServer.TXIndex.TXIndexChain.DB(), lib.DbTxindexPublicKeyPrefix([]byte{})) + apiServer.TXIndex.TXIndexChain.DB(), lib.DbTxindexPublicKeyPrefix([]byte{}), true) // There should be two keys since one is the miner public key and // the other is a dummy public key corresponding to the input of // a block reward txn. Plus one for the seed balance, which creates @@ -1429,12 +1430,13 @@ func TestAPI(t *testing.T) { // Now everything should be reset properly. { prefix := lib.DbTxindexTxIDKey(&lib.BlockHash{})[0] - txnsInTransactionIndex, _ := lib.EnumerateKeysForPrefix(apiServer.TXIndex.TXIndexChain.DB(), []byte{prefix}) + txnsInTransactionIndex, _ := lib.EnumerateKeysForPrefix( + apiServer.TXIndex.TXIndexChain.DB(), []byte{prefix}, true) require.Equal(5+len(apiServer.Params.SeedTxns)+len(apiServer.Params.SeedBalances), len(txnsInTransactionIndex)) } { keysInPublicKeyTable, _ := lib.EnumerateKeysForPrefix( - apiServer.TXIndex.TXIndexChain.DB(), lib.DbTxindexPublicKeyPrefix([]byte{})) + apiServer.TXIndex.TXIndexChain.DB(), lib.DbTxindexPublicKeyPrefix([]byte{}), true) // Three pairs for the block rewards and two pairs for the transactions // we created. require.Equal(10+ From 6e0c3b80e14a47eefdd18cef407c90261bfa39e2 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 21 Mar 2024 18:26:10 -0400 Subject: [PATCH 38/84] Remove relic tag from validator test (#561) --- routes/validators_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/routes/validators_test.go b/routes/validators_test.go index e2f61459..a98260ea 100644 --- a/routes/validators_test.go +++ b/routes/validators_test.go @@ -1,5 +1,3 @@ -//go:build relic - package routes import ( From 24abe77119ed1c703a78c54ba17466b724e323f7 Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Wed, 27 Mar 2024 09:24:29 -0700 Subject: [PATCH 39/84] Update method on CreateAtomicTxnsWrapper. --- routes/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/server.go b/routes/server.go index 7fbc01df..1215c8df 100644 --- a/routes/server.go +++ b/routes/server.go @@ -1424,7 +1424,7 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { }, { "CreateAtomicTxnsWrapper", - []string{"GET"}, + []string{"POST", "OPTIONS"}, RoutePathCreateAtomicTxnsWrapper, fes.CreateAtomicTxnsWrapper, PublicAccess, From 42462cdaa6c603badd14100df7b0c395a9a17db4 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:43:39 -0400 Subject: [PATCH 40/84] Allow orphans in block index (#567) --- scripts/tools/toolslib/chain.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tools/toolslib/chain.go b/scripts/tools/toolslib/chain.go index 2b712f09..b2df849a 100644 --- a/scripts/tools/toolslib/chain.go +++ b/scripts/tools/toolslib/chain.go @@ -19,14 +19,14 @@ func OpenDataDir(dataDir string) (*badger.DB, error) { } // Returns the best chain associated with a badgerDB handle. -func GetBestChainFromBadger(syncedDBHandle *badger.DB) ([]*lib.BlockNode, error) { +func GetBestChainFromBadger(syncedDBHandle *badger.DB, params *lib.DeSoParams) ([]*lib.BlockNode, error) { bestBlockHash := lib.DbGetBestHash(syncedDBHandle, nil, lib.ChainTypeDeSoBlock) if bestBlockHash == nil { return nil, errors.Errorf("GetBestChainFromBadger() could not find a blockchain in the provided db") } // Fetch the block index. - blockIndex, err := lib.GetBlockIndex(syncedDBHandle, false /*bitcoinNodes*/) + blockIndex, err := lib.GetBlockIndex(syncedDBHandle, false /*bitcoinNodes*/, params) if err != nil { return nil, errors.Errorf("GetBestChainFromBadger() could not get blockIndex") } From 782ff5e5fcfe7416db52be760f649650205977a1 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:15:18 -0400 Subject: [PATCH 41/84] Fix max block size logic (#568) --- routes/transaction.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/routes/transaction.go b/routes/transaction.go index b18c42bb..14daf9fb 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -4265,7 +4265,15 @@ func (fes *APIServer) GetTxnConstructionParams(ww http.ResponseWriter, req *http maxBlockSize := requestData.MaxBlockSize if requestData.MaxBlockSize == 0 { - maxBlockSize = fes.Params.MaxBlockSizeBytes + maxBlockSize = fes.Params.MaxBlockSizeBytesPoW + if fes.Params.IsPoSBlockHeight(uint64(fes.blockchain.BlockTip().Height)) { + uncommittedTipView, err := fes.blockchain.GetUncommittedTipView() + if err != nil { + _AddBadRequestError(ww, "GetTxnConstructionParams: Problem getting uncommitted tip view: "+err.Error()) + return + } + maxBlockSize = uncommittedTipView.GetSoftMaxBlockSizeBytesPoS() + } } // Get the fees from the mempool From 5efbb3fc09f1f933f562c203d8b952979da63619 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Fri, 29 Mar 2024 18:08:38 -0400 Subject: [PATCH 42/84] Empty commit to trigger CI From 1e3c41511d4a7504662388611119612fbc5fd8c1 Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Mon, 1 Apr 2024 14:36:58 -0700 Subject: [PATCH 43/84] Use MaxTxnSizeBytesPoS for atomic transaction construction. --- routes/atomic_txns.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/atomic_txns.go b/routes/atomic_txns.go index ead49b31..535bad76 100644 --- a/routes/atomic_txns.go +++ b/routes/atomic_txns.go @@ -76,7 +76,7 @@ func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http. // Validate that: // (1) The resulting transaction is not over the size limit of an atomic transaction. // (2) The resulting wrapper transactions have sufficient fees to cover the wrapper. - if txnSizeBytes > utxoView.Params.MaxBlockSizeBytes/2 { + if txnSizeBytes > utxoView.GlobalParamsEntry.MaxTxnSizeBytesPoS { _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Resulting wrapper transaction too large")) return } From 1c65e5f6c02b3423e27718363d2c596811a59705 Mon Sep 17 00:00:00 2001 From: diamondhands0 <81935176+diamondhands0@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:23:16 -0700 Subject: [PATCH 44/84] Upgrade Badger version (#566) --- cmd/node.go | 2 +- go.mod | 40 +-- go.sum | 342 ++++------------------- routes/exchange_test.go | 2 +- routes/global_state.go | 2 +- routes/server.go | 2 +- routes/user.go | 2 +- scripts/tools/clear_ancestral_records.go | 3 +- scripts/tools/toolslib/chain.go | 2 +- 9 files changed, 75 insertions(+), 322 deletions(-) diff --git a/cmd/node.go b/cmd/node.go index 38d55113..08093982 100644 --- a/cmd/node.go +++ b/cmd/node.go @@ -7,7 +7,7 @@ import ( "github.com/deso-protocol/backend/routes" coreCmd "github.com/deso-protocol/core/cmd" "github.com/deso-protocol/core/lib" - "github.com/dgraph-io/badger/v3" + "github.com/dgraph-io/badger/v4" "github.com/golang/glog" "github.com/kevinburke/twilio-go" ) diff --git a/go.mod b/go.mod index 1046a98b..a5a3ac73 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,13 @@ go 1.20 replace github.com/deso-protocol/core => ../core/ require ( - cloud.google.com/go/storage v1.15.0 + cloud.google.com/go/storage v1.27.0 github.com/btcsuite/btcd v0.21.0-beta github.com/btcsuite/btcutil v1.0.2 github.com/davecgh/go-spew v1.1.1 github.com/deso-protocol/core v0.0.0-00010101000000-000000000000 github.com/deso-protocol/go-deadlock v1.0.0 - github.com/dgraph-io/badger/v3 v3.2103.5 + github.com/dgraph-io/badger/v4 v4.2.0 github.com/fatih/structs v1.1.0 github.com/golang-jwt/jwt/v4 v4.1.0 github.com/golang/glog v1.0.0 @@ -28,24 +28,26 @@ require ( github.com/spf13/cobra v1.1.3 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.1 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 github.com/tyler-smith/go-bip39 v1.1.0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d golang.org/x/image v0.15.0 golang.org/x/sync v0.1.0 - google.golang.org/api v0.46.0 + google.golang.org/api v0.103.0 gopkg.in/DataDog/dd-trace-go.v1 v1.29.0 ) require ( - cloud.google.com/go v0.81.0 // indirect + cloud.google.com/go v0.107.0 // indirect + cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v0.8.0 // indirect github.com/DataDog/datadog-go v4.5.0+incompatible // indirect github.com/Microsoft/go-winio v0.4.16 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect github.com/bwesterb/go-ristretto v1.2.0 // indirect - github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudflare/circl v1.1.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect @@ -67,15 +69,15 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.3 // indirect github.com/google/flatbuffers v2.0.0+incompatible // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 // indirect - github.com/google/uuid v1.2.0 // indirect - github.com/googleapis/gax-go/v2 v2.0.5 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect + github.com/googleapis/gax-go/v2 v2.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.8 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jstemmer/go-junit-report v0.9.1 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7 // indirect github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c // indirect @@ -111,21 +113,19 @@ require ( github.com/vmihailenco/msgpack/v5 v5.3.1 // indirect github.com/vmihailenco/tagparser v0.1.2 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - go.opencensus.io v0.23.0 // indirect - golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect - golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.6.0 // indirect - golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c // indirect + go.opencensus.io v0.24.0 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/oauth2 v0.4.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect golang.org/x/tools v0.6.0 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gonum.org/v1/gonum v0.6.1 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab // indirect - google.golang.org/grpc v1.37.0 // indirect - google.golang.org/protobuf v1.26.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/AlecAivazis/survey.v1 v1.8.7 // indirect gopkg.in/ini.v1 v1.51.0 // indirect gopkg.in/kyokomi/emoji.v1 v1.5.1 // indirect diff --git a/go.sum b/go.sum index 1c3ac420..056a9eb6 100644 --- a/go.sum +++ b/go.sum @@ -5,40 +5,22 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.15.0 h1:Ljj+ZXVEhCr/1+4ZhvtteN1ND7UUsNTlduGclLh8GO0= -cloud.google.com/go/storage v1.15.0/go.mod h1:mjjQMoxxyGH7Jr8K5qrx6N2O0AHsczI61sMNn03GIZI= +cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= @@ -63,7 +45,6 @@ github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= @@ -74,7 +55,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -108,10 +88,10 @@ github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7N github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -120,17 +100,11 @@ github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GK github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -150,8 +124,8 @@ github.com/deso-protocol/go-deadlock v1.0.0 h1:mw0pHy/19zgC+JFBStuQt1+1Ehv5OKA5N github.com/deso-protocol/go-deadlock v1.0.0/go.mod h1:K0Wd2OV2x7ck7SMYDraWerpKjFKUeBqaFcwz21tmkb8= github.com/deso-protocol/go-merkle-tree v1.0.0 h1:9zkI5dQsITYy77s4kbTGPQmZnhQ+LsH/kRdL5l/Yzvg= github.com/deso-protocol/go-merkle-tree v1.0.0/go.mod h1:V/vbg/maaNv6G7zf9VVs645nLFx/jsO2L/awFB/S/ZU= -github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= -github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= +github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= +github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -170,9 +144,6 @@ github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FM github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/go-ethereum v1.9.25 h1:mMiw/zOOtCLdGLWfcekua0qPrJTe7FVIiHJ4IKNTfR0= github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= @@ -195,8 +166,6 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/git-chglog/git-chglog v0.0.0-20200414013904-db796966b373 h1:MHrlpWOOFhCfY1L9iCIUy5cv5HgDtempICenzJt+7ws= github.com/git-chglog/git-chglog v0.0.0-20200414013904-db796966b373/go.mod h1:Dcsy1kii/xFyNad5JqY/d0GO5mu91sungp5xotbm3Yk= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -221,25 +190,16 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -249,7 +209,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -258,47 +217,37 @@ github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI= github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210125172800-10e9aeb4a998/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 h1:zIaiqGYDQwa4HVx5wGRTXbx38Pqxjemn4BP98wpzpXo= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -327,9 +276,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -343,7 +289,6 @@ github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -361,8 +306,6 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -394,7 +337,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -496,7 +438,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -519,13 +460,10 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= @@ -533,7 +471,6 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= @@ -542,8 +479,9 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8 github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -552,8 +490,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= @@ -571,7 +510,6 @@ github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkU github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/unrolled/secure v1.0.8 h1:JaMvKbe4CRt8oyxVXn+xY+6jlqd7pyJNSVkmsBxxQsM= github.com/unrolled/secure v1.0.8/go.mod h1:fO+mEan+FLB0CdEnHf6Q4ZZVNqG+5fuLFnP8p0BXDPI= github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= @@ -593,20 +531,13 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -615,7 +546,6 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -639,16 +569,10 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= @@ -659,26 +583,16 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -696,65 +610,31 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c h1:SgVl/sCtkicsS7psKkje4H9YtjdEl3xsYh7N+5TDHqY= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -765,7 +645,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -774,69 +653,37 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201026173827-119d4633e4d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -859,49 +706,19 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.1 h1:/LSrTrgZtpbXyAR6+0e152SROCkJJSh7goYWVmdPFGc= gonum.org/v1/gonum v0.6.1/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= @@ -913,31 +730,13 @@ google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA= -google.golang.org/api v0.46.0 h1:jkDWHOBIoNSD0OQpq4rtBVu+Rh325MPjXG1rakAp8JU= -google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= +google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -949,60 +748,18 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210420162539-3c870d7478d2/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab h1:dkb90hr43A2Q5as5ZBphcOF2II0+EqfCBqGp7qFSpN4= -google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1011,11 +768,11 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/AlecAivazis/survey.v1 v1.8.7 h1:oBJqtgsyBLg9K5FK9twNUbcPnbCPoh+R9a+7nag3qJM= gopkg.in/AlecAivazis/survey.v1 v1.8.7/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= gopkg.in/DataDog/dd-trace-go.v1 v1.29.0 h1:3C1EEjgFTPqrnS2SXuSqkBbZGacIOPJ7ScGJk4nrP9s= @@ -1023,7 +780,6 @@ gopkg.in/DataDog/dd-trace-go.v1 v1.29.0/go.mod h1:FLwUDeuH0z5hkvgvd04/M3MHQN4AF5 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -1055,12 +811,8 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w= mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ= pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/routes/exchange_test.go b/routes/exchange_test.go index be9add02..9f0d1674 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -17,7 +17,7 @@ import ( coreCmd "github.com/deso-protocol/core/cmd" "github.com/deso-protocol/core/lib" - "github.com/dgraph-io/badger/v3" + "github.com/dgraph-io/badger/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/routes/global_state.go b/routes/global_state.go index 3f761b3b..85d5f1fd 100644 --- a/routes/global_state.go +++ b/routes/global_state.go @@ -10,7 +10,7 @@ import ( "github.com/deso-protocol/core/lib" - "github.com/dgraph-io/badger/v3" + "github.com/dgraph-io/badger/v4" "github.com/nyaruka/phonenumbers" "github.com/pkg/errors" ) diff --git a/routes/server.go b/routes/server.go index 2a90dd2f..628e08c4 100644 --- a/routes/server.go +++ b/routes/server.go @@ -19,7 +19,7 @@ import ( "github.com/tyler-smith/go-bip39" "github.com/deso-protocol/core/lib" - "github.com/dgraph-io/badger/v3" + "github.com/dgraph-io/badger/v4" "github.com/golang/glog" "github.com/kevinburke/twilio-go" muxtrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/gorilla/mux" diff --git a/routes/user.go b/routes/user.go index 410a94d2..2484e844 100644 --- a/routes/user.go +++ b/routes/user.go @@ -18,7 +18,7 @@ import ( "github.com/holiman/uint256" "github.com/btcsuite/btcd/btcec" - "github.com/dgraph-io/badger/v3" + "github.com/dgraph-io/badger/v4" "github.com/gorilla/mux" "github.com/deso-protocol/core/lib" diff --git a/scripts/tools/clear_ancestral_records.go b/scripts/tools/clear_ancestral_records.go index 7f862488..1b5aa1c8 100644 --- a/scripts/tools/clear_ancestral_records.go +++ b/scripts/tools/clear_ancestral_records.go @@ -2,9 +2,10 @@ package main import ( "fmt" + "github.com/deso-protocol/backend/scripts/tools/toolslib" "github.com/deso-protocol/core/lib" - "github.com/dgraph-io/badger/v3" + "github.com/dgraph-io/badger/v4" "github.com/pkg/errors" ) diff --git a/scripts/tools/toolslib/chain.go b/scripts/tools/toolslib/chain.go index b2df849a..032b5662 100644 --- a/scripts/tools/toolslib/chain.go +++ b/scripts/tools/toolslib/chain.go @@ -2,7 +2,7 @@ package toolslib import ( "github.com/deso-protocol/core/lib" - "github.com/dgraph-io/badger/v3" + "github.com/dgraph-io/badger/v4" "github.com/pkg/errors" ) From 993b149c898ff04c34ae4ae8ec4e65a7954b2742 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Mon, 1 Apr 2024 19:36:22 -0400 Subject: [PATCH 45/84] Fix Update global params tests (#571) --- routes/admin_transaction_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/routes/admin_transaction_test.go b/routes/admin_transaction_test.go index 20ecfd4d..fd8229e0 100644 --- a/routes/admin_transaction_test.go +++ b/routes/admin_transaction_test.go @@ -97,20 +97,20 @@ func TestUpdateGlobalParams(t *testing.T) { // Update all GlobalParam fields. updateGlobalParams(&UpdateGlobalParamsRequest{ UpdaterPublicKeyBase58Check: senderPkString, - MinimumNetworkFeeNanosPerKB: 99, + MinimumNetworkFeeNanosPerKB: 1000, StakeLockupEpochDuration: 4, ValidatorJailEpochDuration: 4, LeaderScheduleMaxNumValidators: 101, ValidatorSetMaxNumValidators: 102, EpochDurationNumBlocks: 3601, JailInactiveValidatorGracePeriodEpochs: 49, - MinFeeRateNanosPerKB: 99, + MinFeeRateNanosPerKB: 1000, }) } { // Verify all updated GlobalParam fields. globalParams := getGlobalParams() - require.Equal(t, globalParams.MinimumNetworkFeeNanosPerKB, uint64(99)) + require.Equal(t, globalParams.MinimumNetworkFeeNanosPerKB, uint64(1000)) require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(4)) require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(4)) require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(101)) @@ -122,15 +122,15 @@ func TestUpdateGlobalParams(t *testing.T) { // Update only one GlobalParam field. updateGlobalParams(&UpdateGlobalParamsRequest{ UpdaterPublicKeyBase58Check: senderPkString, - MinimumNetworkFeeNanosPerKB: 99, + MinimumNetworkFeeNanosPerKB: 1000, JailInactiveValidatorGracePeriodEpochs: 50, - MinFeeRateNanosPerKB: 99, + MinFeeRateNanosPerKB: 1000, }) } { // Verify updated GlobalParam field. And other fields retain old values. globalParams := getGlobalParams() - require.Equal(t, globalParams.MinimumNetworkFeeNanosPerKB, uint64(99)) + require.Equal(t, globalParams.MinimumNetworkFeeNanosPerKB, uint64(1000)) require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(4)) require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(4)) require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(101)) From 38c3cf7ad49d7e327411e043bff94bc71bcefae5 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:20:25 -0400 Subject: [PATCH 46/84] trigger build (#572) From c32371570aa84672043216f707958a154a1598d1 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:53:37 -0400 Subject: [PATCH 47/84] trigger build (#573) From 323b8bd2fedab20e2ac00ee7db762c53c924367d Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:23:41 -0400 Subject: [PATCH 48/84] trigger build (#574) From 5e71dafae22f7725d6b4722813400b93a4b27d6e Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Wed, 3 Apr 2024 18:40:42 -0400 Subject: [PATCH 49/84] Empty commit to trigger CI From 99e2e4ab8e31bd674e9924ec22b53ab18b349cb8 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 4 Apr 2024 10:40:15 -0400 Subject: [PATCH 50/84] bls pub key enhancements build (#576) From eb8bc223b6b66eb7e8ab5b7f91f57160221d9d60 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 4 Apr 2024 10:58:49 -0400 Subject: [PATCH 51/84] allow txn relay in needs blocks build (#577) From c7c9a7818f518bdc8e9c84c9aceb7c1f04d508da Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 4 Apr 2024 11:39:45 -0400 Subject: [PATCH 52/84] fix txn relay pos check build (#578) From fca695c0142cb3c430e6e3a3470416cc7700e03f Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Thu, 4 Apr 2024 12:52:46 -0700 Subject: [PATCH 53/84] Subsidized Update Profile Scaffolding --- cmd/run.go | 6 ++++++ config/config.go | 6 ++++++ routes/base.go | 3 +++ routes/server.go | 12 +++++++++++- routes/transaction.go | 5 +++++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/cmd/run.go b/cmd/run.go index 02486a57..8f8731a1 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -79,6 +79,12 @@ func init() { "be allowed to be used this many times to receive starter DESO. Set this to a higher value "+ "if you want users to be able to create multiple accounts more easily.") + // Transaction Subsidization + runCmd.PersistentFlags().String("transaction-subsidization-seed", "", + "If specified, a seed phrase from which user transactions may be subsidized"+ + " via atomic transactions. For example, this seed is used in constructing small basic transfers"+ + " that can cover the fees of an update profile for those users which do not yet have DESO.") + // Global State runCmd.PersistentFlags().String("global-state-remote-node", "", "The IP:PORT or DOMAIN:PORT corresponding to a node that can be used to "+ diff --git a/config/config.go b/config/config.go index 81b9b47a..5496b34e 100644 --- a/config/config.go +++ b/config/config.go @@ -28,6 +28,9 @@ type Config struct { MinSatoshisForProfile uint64 PhoneNumberUseThreshold uint64 + // Transaction Subsidization + TransactionSubsidizationSeed string + // Global State GlobalStateRemoteNode string GlobalStateRemoteSecret string @@ -130,6 +133,9 @@ func LoadConfig(coreConfig *coreCmd.Config) *Config { config.MinSatoshisForProfile = viper.GetUint64("min-satoshis-for-profile") config.PhoneNumberUseThreshold = viper.GetUint64("phone-number-use-threshold") + // Transaction Subsidization + config.TransactionSubsidizationSeed = viper.GetString("transaction-subsidization-seed") + // Global State config.GlobalStateRemoteNode = viper.GetString("global-state-remote-node") config.GlobalStateRemoteSecret = viper.GetString("global-state-remote-secret") diff --git a/routes/base.go b/routes/base.go index ce0359a0..e8497d78 100644 --- a/routes/base.go +++ b/routes/base.go @@ -350,6 +350,8 @@ type GetAppStateResponse struct { HasJumioIntegration bool BuyWithETH bool + HasTransactionSubsidizationSeed bool + USDCentsPerDeSoExchangeRate uint64 USDCentsPerDeSoCoinbase uint64 USDCentsPerDeSoBlockchainDotCom uint64 @@ -412,6 +414,7 @@ func (fes *APIServer) GetAppState(ww http.ResponseWriter, req *http.Request) { HasWyreIntegration: fes.IsConfiguredForWyre(), HasJumioIntegration: fes.IsConfiguredForJumio(), BuyWithETH: fes.IsConfiguredForETH(), + HasTransactionSubsidizationSeed: fes.Config.TransactionSubsidizationSeed != "", USDCentsPerDeSoExchangeRate: fes.GetExchangeDeSoPrice(), USDCentsPerDeSoCoinbase: fes.MostRecentCoinbasePriceUSDCents, USDCentsPerDeSoBlockchainDotCom: fes.MostRecentBlockchainDotComPriceUSDCents, diff --git a/routes/server.go b/routes/server.go index 8c84afde..5bd0c7ac 100644 --- a/routes/server.go +++ b/routes/server.go @@ -51,6 +51,7 @@ const ( RoutePathGetTxn = "/api/v0/get-txn" RoutePathSubmitTransaction = "/api/v0/submit-transaction" RoutePathUpdateProfile = "/api/v0/update-profile" + RoutePathSubsidizedUpdateProfile = "/api/v0/subsidized-update-profile" RoutePathExchangeBitcoin = "/api/v0/exchange-bitcoin" RoutePathSendDeSo = "/api/v0/send-deso" RoutePathSubmitPost = "/api/v0/submit-post" @@ -747,6 +748,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.UpdateProfile, PublicAccess, }, + { + "SubsidizedUpdateProfile", + []string{"POST", "OPTIONS"}, + RoutePathSubsidizedUpdateProfile, + fes.SubsidizedUpdateProfile, + PublicAccess, + }, { "GetProfiles", []string{"POST", "OPTIONS"}, @@ -2738,7 +2746,7 @@ func (fes *APIServer) StartExchangePriceMonitoring() { }() } -// Monitor balances for starter deso seed and buy deso seed +// Monitor balances for starter deso seed, buy deso seed, and transaction subsidization seed func (fes *APIServer) StartSeedBalancesMonitoring() { go func() { out: @@ -2759,6 +2767,8 @@ func (fes *APIServer) StartSeedBalancesMonitoring() { } fes.logBalanceForSeed(fes.Config.StarterDESOSeed, "STARTER_DESO", tags) fes.logBalanceForSeed(fes.Config.BuyDESOSeed, "BUY_DESO", tags) + fes.logBalanceForSeed(fes.Config.TransactionSubsidizationSeed, + "TRANSACTION_SUBSIDIZATION_SEED", tags) for label, publicKey := range fes.Config.PublicKeyBalancesToMonitor { fes.logBalanceForPublicKey(publicKey, label, tags) } diff --git a/routes/transaction.go b/routes/transaction.go index 14daf9fb..f46b40e4 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -620,6 +620,11 @@ func GetBalanceForPublicKeyUsingUtxoView( return totalBalanceNanos, nil } +// SubsidizedUpdateProfile +func (fes *APIServer) SubsidizedUpdateProfile(ww http.ResponseWriter, req *http.Request) { + _AddBadRequestError(ww, "SubsidizedUpdateProfile: Not implemented") +} + // ExchangeBitcoinRequest ... type ExchangeBitcoinRequest struct { // The public key of the user who we're creating the burn for. From 01cff1f8922a5963ab7c9dbf2e7eb9a5ddedcf23 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Thu, 4 Apr 2024 17:37:48 -0400 Subject: [PATCH 54/84] Empty commit to trigger CI From 998a1b6a74966f21e92e55b12c14a3b3ec20bf57 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Thu, 4 Apr 2024 17:56:57 -0400 Subject: [PATCH 55/84] Fix backend CI --- routes/admin_transaction_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/admin_transaction_test.go b/routes/admin_transaction_test.go index fd8229e0..44eaf3cc 100644 --- a/routes/admin_transaction_test.go +++ b/routes/admin_transaction_test.go @@ -90,7 +90,7 @@ func TestUpdateGlobalParams(t *testing.T) { require.Equal(t, globalParams.StakeLockupEpochDuration, uint64(3)) require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(3)) require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(100)) - require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(10)) + require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(144)) require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(3)) } { From 08039b75da88be7be332b06c47c449ef8e1cb4c8 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:41:44 -0400 Subject: [PATCH 56/84] Use GetCurrentGlobalParamsEntry instead of GlobalParamsEntry (#580) --- .gitignore | 2 ++ routes/base.go | 2 +- routes/nft.go | 32 ++++++++++++++++---------------- routes/shared.go | 5 +++-- routes/transaction.go | 4 ++-- routes/user.go | 2 +- routes/verify.go | 4 +++- 7 files changed, 28 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 0ff977e4..92068074 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ backend .idea .vscode mem.log + +__debug_* \ No newline at end of file diff --git a/routes/base.go b/routes/base.go index ce0359a0..bfdc91ce 100644 --- a/routes/base.go +++ b/routes/base.go @@ -389,7 +389,7 @@ func (fes *APIServer) GetAppState(ww http.ResponseWriter, req *http.Request) { } // Compute a default fee rate. - globalParams := utxoView.GlobalParamsEntry + globalParams := utxoView.GetCurrentGlobalParamsEntry() defaultFeeRateNanosPerKB := fes.MinFeeRateNanosPerKB if globalParams != nil && globalParams.MinimumNetworkFeeNanosPerKB > 0 { defaultFeeRateNanosPerKB = globalParams.MinimumNetworkFeeNanosPerKB diff --git a/routes/nft.go b/routes/nft.go index c6affae5..65fbe757 100644 --- a/routes/nft.go +++ b/routes/nft.go @@ -124,15 +124,15 @@ func (fes *APIServer) CreateNFT(ww http.ResponseWriter, req *http.Request) { } else if requestData.UpdaterPublicKeyBase58Check == "" { _AddBadRequestError(ww, fmt.Sprintf("CreateNFT: Must include UpdaterPublicKeyBase58Check")) return - } else if utxoView.GlobalParamsEntry.MaxCopiesPerNFT == 0 { + } else if utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT == 0 { _AddBadRequestError(ww, "NFT minting has not been enabled yet. Check back soon :)") return - } else if requestData.NumCopies <= 0 || requestData.NumCopies > int(utxoView.GlobalParamsEntry.MaxCopiesPerNFT) { + } else if requestData.NumCopies <= 0 || requestData.NumCopies > int(utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT) { _AddBadRequestError(ww, fmt.Sprintf( "CreateNFT: NumCopies must be between %d and %d, received: %d", - 1, utxoView.GlobalParamsEntry.MaxCopiesPerNFT, requestData.NumCopies)) + 1, utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT, requestData.NumCopies)) return } else if requestData.NFTRoyaltyToCreatorBasisPoints < 0 || requestData.NFTRoyaltyToCreatorBasisPoints > int(fes.Params.MaxNFTRoyaltyBasisPoints) { @@ -238,7 +238,7 @@ func (fes *APIServer) CreateNFT(ww http.ResponseWriter, req *http.Request) { return } - nftFee := utxoView.GlobalParamsEntry.CreateNFTFeeNanos * uint64(requestData.NumCopies) + nftFee := utxoView.GetCurrentGlobalParamsEntry().CreateNFTFeeNanos * uint64(requestData.NumCopies) extraData, err := EncodeExtraDataMap(requestData.ExtraData) if err != nil { @@ -342,10 +342,10 @@ func (fes *APIServer) UpdateNFT(ww http.ResponseWriter, req *http.Request) { _AddBadRequestError(ww, fmt.Sprintf("UpdateNFT: Must include UpdaterPublicKeyBase58Check")) return - } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GlobalParamsEntry.MaxCopiesPerNFT) { + } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT) { _AddBadRequestError(ww, fmt.Sprintf( "UpdateNFT: SerialNumbers must be between %d and %d, received: %d", - 1, utxoView.GlobalParamsEntry.MaxCopiesPerNFT, requestData.SerialNumber)) + 1, utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT, requestData.SerialNumber)) return } else if requestData.MinBidAmountNanos < 0 { @@ -492,10 +492,10 @@ func (fes *APIServer) CreateNFTBid(ww http.ResponseWriter, req *http.Request) { _AddBadRequestError(ww, fmt.Sprintf("CreateNFTBid: Must include UpdaterPublicKeyBase58Check")) return - } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GlobalParamsEntry.MaxCopiesPerNFT) { + } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT) { _AddBadRequestError(ww, fmt.Sprintf( "CreateNFTBid: SerialNumbers must be between %d and %d, received: %d", - 1, utxoView.GlobalParamsEntry.MaxCopiesPerNFT, requestData.SerialNumber)) + 1, utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT, requestData.SerialNumber)) return } else if requestData.BidAmountNanos < 0 { @@ -654,10 +654,10 @@ func (fes *APIServer) AcceptNFTBid(ww http.ResponseWriter, req *http.Request) { "AcceptNFTBid: Must include UpdaterPublicKeyBase58Check and BidderPublicKeyBase58Check")) return - } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GlobalParamsEntry.MaxCopiesPerNFT) { + } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT) { _AddBadRequestError(ww, fmt.Sprintf( "AcceptNFTBid: SerialNumbers must be between %d and %d, received: %d", - 1, utxoView.GlobalParamsEntry.MaxCopiesPerNFT, requestData.SerialNumber)) + 1, utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT, requestData.SerialNumber)) return } else if requestData.BidAmountNanos < 0 { @@ -1573,10 +1573,10 @@ func (fes *APIServer) TransferNFT(ww http.ResponseWriter, req *http.Request) { _AddBadRequestError(ww, fmt.Sprintf("TransferNFT: Must include UpdaterPublicKeyBase58Check")) return - } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GlobalParamsEntry.MaxCopiesPerNFT) { + } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT) { _AddBadRequestError(ww, fmt.Sprintf( "TransferNFT: SerialNumbers must be between %d and %d, received: %d", - 1, utxoView.GlobalParamsEntry.MaxCopiesPerNFT, requestData.SerialNumber)) + 1, utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT, requestData.SerialNumber)) return } @@ -1730,10 +1730,10 @@ func (fes *APIServer) AcceptNFTTransfer(ww http.ResponseWriter, req *http.Reques _AddBadRequestError(ww, fmt.Sprintf("AcceptNFTTransfer: Must include UpdaterPublicKeyBase58Check")) return - } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GlobalParamsEntry.MaxCopiesPerNFT) { + } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT) { _AddBadRequestError(ww, fmt.Sprintf( "AcceptNFTTransfer: SerialNumbers must be between %d and %d, received: %d", - 1, utxoView.GlobalParamsEntry.MaxCopiesPerNFT, requestData.SerialNumber)) + 1, utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT, requestData.SerialNumber)) return } @@ -1869,10 +1869,10 @@ func (fes *APIServer) BurnNFT(ww http.ResponseWriter, req *http.Request) { _AddBadRequestError(ww, fmt.Sprintf("BurnNFT: Must include UpdaterPublicKeyBase58Check")) return - } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GlobalParamsEntry.MaxCopiesPerNFT) { + } else if requestData.SerialNumber <= 0 || requestData.SerialNumber > int(utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT) { _AddBadRequestError(ww, fmt.Sprintf( "BurnNFT: SerialNumbers must be between %d and %d, received: %d", - 1, utxoView.GlobalParamsEntry.MaxCopiesPerNFT, requestData.SerialNumber)) + 1, utxoView.GetCurrentGlobalParamsEntry().MaxCopiesPerNFT, requestData.SerialNumber)) return } diff --git a/routes/shared.go b/routes/shared.go index d5a67200..0a38d046 100644 --- a/routes/shared.go +++ b/routes/shared.go @@ -394,8 +394,9 @@ func (fes *APIServer) SendSeedDeSo(recipientPkBytes []byte, amountNanos uint64, } minFee := fes.MinFeeRateNanosPerKB - if utxoView.GlobalParamsEntry != nil && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB > 0 { - minFee = utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB + if utxoView.GetCurrentGlobalParamsEntry() != nil && + utxoView.GetCurrentGlobalParamsEntry().MinimumNetworkFeeNanosPerKB > 0 { + minFee = utxoView.GetCurrentGlobalParamsEntry().MinimumNetworkFeeNanosPerKB } _, _, _, _, err = fes.blockchain.AddInputsAndChangeToTransaction(txn, minFee, fes.backendServer.GetMempool()) if err != nil { diff --git a/routes/transaction.go b/routes/transaction.go index 14daf9fb..301c4339 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -478,7 +478,7 @@ func (fes *APIServer) CompProfileCreation(profilePublicKey []byte, userMetadata return 0, nil, nil } // Additional fee is set to the create profile fee when we are creating a profile - additionalFees := utxoView.GlobalParamsEntry.CreateProfileFeeNanos + additionalFees := utxoView.GetCurrentGlobalParamsEntry().CreateProfileFeeNanos if additionalFees == 0 { return 0, nil, nil } @@ -496,7 +496,7 @@ func (fes *APIServer) CompProfileCreation(profilePublicKey []byte, userMetadata if err != nil { return 0, nil, errors.Wrap(fmt.Errorf("UpdateProfile: error getting current balance: %v", err), "") } - createProfileFeeNanos := utxoView.GlobalParamsEntry.CreateProfileFeeNanos + createProfileFeeNanos := utxoView.GetCurrentGlobalParamsEntry().CreateProfileFeeNanos // If a user is jumio verified, we just comp the profile even if their balance is greater than the create profile fee. // If a user has a phone number verified but is not jumio verified, we need to check that they haven't spent all their diff --git a/routes/user.go b/routes/user.go index 2484e844..b837375e 100644 --- a/routes/user.go +++ b/routes/user.go @@ -99,7 +99,7 @@ func (fes *APIServer) updateUsersStateless(userList []*User, skipForLeaderboard if err != nil { return nil, fmt.Errorf("updateUserFields: Error calling GetAugmentedUtxoViewForPublicKey: %v", err) } - globalParams := utxoView.GlobalParamsEntry + globalParams := utxoView.GetCurrentGlobalParamsEntry() for _, user := range userList { // If we get an error updating the user, log it but don't stop the show. if err = fes.updateUserFieldsStateless( diff --git a/routes/verify.go b/routes/verify.go index 9c9910eb..8ac0fe7e 100644 --- a/routes/verify.go +++ b/routes/verify.go @@ -143,7 +143,9 @@ func (fes *APIServer) canUserCreateProfile(userMetadata *UserMetadata, utxoView // User can create a profile if they have a phone number or if they have enough DeSo to cover the create profile fee. // User can also create a profile if they've successfully filled out a captcha. // The PhoneNumber is only set if the user has passed phone number verification. - if userMetadata.PhoneNumber != "" || totalBalanceNanos >= utxoView.GlobalParamsEntry.CreateProfileFeeNanos || userMetadata.LastHcaptchaBlockHeight > 0 { + if userMetadata.PhoneNumber != "" || + totalBalanceNanos >= utxoView.GetCurrentGlobalParamsEntry().CreateProfileFeeNanos || + userMetadata.LastHcaptchaBlockHeight > 0 { return true, nil } From f18244f1db8f1a1e90571ac20334cffa8a4c372a Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Thu, 21 Mar 2024 14:32:02 -0700 Subject: [PATCH 57/84] Simple CreateAtomicTxnsWrapper scaffolding. --- routes/atomic_txns.go | 106 ++++++++++++++++++++++++++++++++++++++++++ routes/server.go | 10 ++++ 2 files changed, 116 insertions(+) create mode 100644 routes/atomic_txns.go diff --git a/routes/atomic_txns.go b/routes/atomic_txns.go new file mode 100644 index 00000000..ead49b31 --- /dev/null +++ b/routes/atomic_txns.go @@ -0,0 +1,106 @@ +package routes + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "github.com/deso-protocol/core/lib" + "io" + "net/http" +) + +type CreateAtomicTxnsWrapperRequest struct { + Transactions []*lib.MsgDeSoTxn + ExtraData map[string]string +} + +type CreateAtomicTxnsWrapperResponse struct { + // TransactionsWrapped as a helpful sanity check for the caller of the + // CreateAtomicTxnsWrapper endpoint. That being said, the caller should + // also sanity check that the returned wrapper transaction has the atomic + // transactions ordered correctly. + TransactionsWrapped uint64 `safeForLogging:"true"` + + // TotalFeeNanos represents the total fees paid cumulatively by all + // wrapper atomic transactions and is consistent with the + // returned Transaction.TxnFeeNanos field. + TotalFeeNanos uint64 + Transaction *lib.MsgDeSoTxn + TransactionHex string +} + +func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := CreateAtomicTxnsWrapperRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Error parsing request body: %v", err)) + return + } + + // Grab a view (needed for getting global params, etc). + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Error getting utxoView: %v", err)) + return + } + + // Validate the request data. + if len(requestData.Transactions) == 0 { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: must have at least one transaction "+ + "in Transactions")) + return + } + + // Encode the ExtraData map. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem encoding ExtraData: %v", err)) + return + } + + // Construct the atomic transactions wrapper transaction type. + txn, totalFees, err := fes.blockchain.CreateAtomicTxnsWrapper(requestData.Transactions, extraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem constructing transaction: %v", err)) + return + } + + // Serialize the transaction. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem serializing transaction: %v", err)) + return + } + txnSizeBytes := uint64(len(txnBytes)) + + // Validate that: + // (1) The resulting transaction is not over the size limit of an atomic transaction. + // (2) The resulting wrapper transactions have sufficient fees to cover the wrapper. + if txnSizeBytes > utxoView.Params.MaxBlockSizeBytes/2 { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Resulting wrapper transaction too large")) + return + } + if txnSizeBytes != 0 && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB != 0 { + // Check for overflow or minimum network fee not met. + if totalFees != ((totalFees*1000)/1000) || + (totalFees*1000)/uint64(txnSizeBytes) < utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Transactions used to construct"+ + " atomic transaction do not cumulatively pay sufficient network fees to cover wrapper")) + return + } + } + + // Construct a response. + res := CreateAtomicTxnsWrapperResponse{ + TransactionsWrapped: uint64(len(txn.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns)), + TotalFeeNanos: totalFees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, + fmt.Sprintf("CreateAtomicTxnsWrapper: Problem serializing object to JSON: %v", err)) + return + } +} diff --git a/routes/server.go b/routes/server.go index 628e08c4..4c3cd6f9 100644 --- a/routes/server.go +++ b/routes/server.go @@ -331,6 +331,9 @@ const ( RoutePathCoinUnlock = "/api/v0/coin-unlock" RoutePathLockupYieldCurvePoints = "/api/v0/lockup-yield-curve-points" RoutePathLockedBalanceEntries = "/api/v0/locked-balance-entries" + + // atomic_txns.go + RoutePathCreateAtomicTxnsWrapper = "/api/v0/create-atomic-txns-wrapper" ) // APIServer provides the interface between the blockchain and things like the @@ -1419,6 +1422,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.LockedBalanceEntries, PublicAccess, }, + { + "CreateAtomicTxnsWrapper", + []string{"GET"}, + RoutePathCreateAtomicTxnsWrapper, + fes.CreateAtomicTxnsWrapper, + PublicAccess, + }, // Jumio Routes { "JumioBegin", From b7f9fa7761bab485ff92cc62665dc2827c8cb435 Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Wed, 27 Mar 2024 09:24:29 -0700 Subject: [PATCH 58/84] Update method on CreateAtomicTxnsWrapper. --- routes/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/server.go b/routes/server.go index 4c3cd6f9..8c84afde 100644 --- a/routes/server.go +++ b/routes/server.go @@ -1424,7 +1424,7 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { }, { "CreateAtomicTxnsWrapper", - []string{"GET"}, + []string{"POST", "OPTIONS"}, RoutePathCreateAtomicTxnsWrapper, fes.CreateAtomicTxnsWrapper, PublicAccess, From c1cff03d7124e713e5a00afdea172547c9aac594 Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Mon, 1 Apr 2024 14:36:58 -0700 Subject: [PATCH 59/84] Use MaxTxnSizeBytesPoS for atomic transaction construction. --- routes/atomic_txns.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/atomic_txns.go b/routes/atomic_txns.go index ead49b31..535bad76 100644 --- a/routes/atomic_txns.go +++ b/routes/atomic_txns.go @@ -76,7 +76,7 @@ func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http. // Validate that: // (1) The resulting transaction is not over the size limit of an atomic transaction. // (2) The resulting wrapper transactions have sufficient fees to cover the wrapper. - if txnSizeBytes > utxoView.Params.MaxBlockSizeBytes/2 { + if txnSizeBytes > utxoView.GlobalParamsEntry.MaxTxnSizeBytesPoS { _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Resulting wrapper transaction too large")) return } From 449ef5fb0087cef24fecf71a355937105d8b4027 Mon Sep 17 00:00:00 2001 From: diamondhands Date: Thu, 4 Apr 2024 20:29:02 -0700 Subject: [PATCH 60/84] Fix MaxTxnSizeBytes bug --- routes/atomic_txns.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/atomic_txns.go b/routes/atomic_txns.go index 535bad76..72b94991 100644 --- a/routes/atomic_txns.go +++ b/routes/atomic_txns.go @@ -76,7 +76,7 @@ func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http. // Validate that: // (1) The resulting transaction is not over the size limit of an atomic transaction. // (2) The resulting wrapper transactions have sufficient fees to cover the wrapper. - if txnSizeBytes > utxoView.GlobalParamsEntry.MaxTxnSizeBytesPoS { + if txnSizeBytes > utxoView.GetCurrentGlobalParamsEntry().MaxTxnSizeBytesPoS { _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Resulting wrapper transaction too large")) return } From b93bb61606e7c92539a24df88d6030c193122675 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Fri, 5 Apr 2024 14:57:50 -0400 Subject: [PATCH 61/84] Empty commit for CI From e1184017b4822548dcefad4f0d21c764a276a894 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Fri, 5 Apr 2024 16:10:48 -0400 Subject: [PATCH 62/84] Empty commit for CI From b1d7ac33f91ce9d56fad16604dde7a491166f7a0 Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Fri, 5 Apr 2024 17:49:57 -0700 Subject: [PATCH 63/84] Implemented Subsidized Update Profile. --- routes/transaction.go | 383 +++++++++++++++++++++++++++++++++--------- 1 file changed, 302 insertions(+), 81 deletions(-) diff --git a/routes/transaction.go b/routes/transaction.go index f46b40e4..8d9cfec8 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "github.com/tyler-smith/go-bip39" "io" "math/big" "net/http" @@ -318,89 +319,12 @@ func (fes *APIServer) UpdateProfile(ww http.ResponseWriter, req *http.Request) { profilePublicKey = profilePublicKeyBytess } - if len(requestData.NewUsername) > 0 && strings.Index(requestData.NewUsername, fes.PublicKeyBase58Prefix) == 0 { - _AddBadRequestError(ww, fmt.Sprintf( - "UpdateProfile: Username cannot start with %s", fes.PublicKeyBase58Prefix)) - return - } - - if uint64(len([]byte(requestData.NewUsername))) > utxoView.Params.MaxUsernameLengthBytes { - _AddBadRequestError(ww, lib.RuleErrorProfileUsernameTooLong.Error()) + // Validate the request. + if err := fes.ValidateAndConvertUpdateProfileRequest(&requestData, profilePublicKey, utxoView); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Problem validating request: %v", err)) return } - if uint64(len([]byte(requestData.NewDescription))) > utxoView.Params.MaxUserDescriptionLengthBytes { - _AddBadRequestError(ww, lib.RuleErrorProfileDescriptionTooLong.Error()) - return - } - - // If an image is set on the request then resize it. - // Convert image to base64 by stripping the data: prefix. - if requestData.NewProfilePic != "" { - // split on base64 to get the extension - extensionSplit := strings.Split(requestData.NewProfilePic, ";base64") - if len(extensionSplit) != 2 { - _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Problem parsing profile pic extension: %v", err)) - return - } - extension := extensionSplit[0] - switch { - case strings.Contains(extension, "image/png"): - extension = ".png" - case strings.Contains(extension, "image/jpeg"): - extension = ".jpeg" - case strings.Contains(extension, "image/webp"): - extension = ".webp" - case strings.Contains(extension, "image/gif"): - extension = ".gif" - default: - _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Unsupported image type: %v", extension)) - return - } - var resizedImageBytes []byte - resizedImageBytes, err = resizeAndConvertToWebp( - requestData.NewProfilePic, uint(fes.Params.MaxProfilePicDimensions), extension) - if err != nil { - _AddBadRequestError(ww, fmt.Sprintf("Problem resizing profile picture: %v", err)) - return - } - // Convert the image back into base64 - webpBase64 := base64.StdEncoding.EncodeToString(resizedImageBytes) - requestData.NewProfilePic = "data:image/webp;base64," + webpBase64 - if uint64(len([]byte(requestData.NewProfilePic))) > utxoView.Params.MaxProfilePicLengthBytes { - _AddBadRequestError(ww, lib.RuleErrorMaxProfilePicSize.Error()) - return - } - } - - // CreatorBasisPoints > 0 < max, uint64 can't be less than zero - if requestData.NewCreatorBasisPoints > fes.Params.MaxCreatorBasisPoints { - _AddBadRequestError(ww, fmt.Sprintf( - "UpdateProfile: Creator percentage must be less than %v percent", - fes.Params.MaxCreatorBasisPoints/100)) - return - } - - // Verify that this username doesn't exist in the mempool. - if len(requestData.NewUsername) > 0 { - - utxoView.GetProfileEntryForUsername([]byte(requestData.NewUsername)) - existingProfile, usernameExists := utxoView.ProfileUsernameToProfileEntry[lib.MakeUsernameMapKey([]byte(requestData.NewUsername))] - if usernameExists && existingProfile != nil && !existingProfile.IsDeleted() { - // Check that the existing profile does not belong to the profile public key - if utxoView.GetPKIDForPublicKey(profilePublicKey) != utxoView.GetPKIDForPublicKey(existingProfile.PublicKey) { - _AddBadRequestError(ww, fmt.Sprintf( - "UpdateProfile: Username %v already exists", string(existingProfile.Username))) - return - } - - } - if !lib.UsernameRegex.Match([]byte(requestData.NewUsername)) { - _AddBadRequestError(ww, lib.RuleErrorInvalidUsername.Error()) - return - } - } - extraData, err := EncodeExtraDataMap(requestData.ExtraData) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Problem encoding ExtraData: %v", err)) @@ -470,6 +394,93 @@ func (fes *APIServer) UpdateProfile(ww http.ResponseWriter, req *http.Request) { } } +func (fes *APIServer) ValidateAndConvertUpdateProfileRequest( + requestData *UpdateProfileRequest, + profilePublicKey []byte, + utxoView *lib.UtxoView, +) error { + if len(requestData.NewUsername) > 0 && strings.Index(requestData.NewUsername, fes.PublicKeyBase58Prefix) == 0 { + return fmt.Errorf( + "ValidateAndConvertUpdateProfileRequest: Username cannot start with %s", fes.PublicKeyBase58Prefix) + } + + if uint64(len([]byte(requestData.NewUsername))) > utxoView.Params.MaxUsernameLengthBytes { + return errors.Wrap(lib.RuleErrorProfileUsernameTooLong, "ValidateAndConvertUpdateProfileRequest") + } + + if uint64(len([]byte(requestData.NewDescription))) > utxoView.Params.MaxUserDescriptionLengthBytes { + return errors.Wrap(lib.RuleErrorProfileDescriptionTooLong, "ValidateAndConvertUpdateProfileRequest") + } + + // If an image is set on the request then resize it. + // Convert image to base64 by stripping the data: prefix. + if requestData.NewProfilePic != "" { + // split on base64 to get the extension + extensionSplit := strings.Split(requestData.NewProfilePic, ";base64") + if len(extensionSplit) != 2 { + return fmt.Errorf("ValidateAndConvertUpdateProfileRequest: " + + "Problem parsing profile pic extension; invalid extension split") + } + extension := extensionSplit[0] + switch { + case strings.Contains(extension, "image/png"): + extension = ".png" + case strings.Contains(extension, "image/jpeg"): + extension = ".jpeg" + case strings.Contains(extension, "image/webp"): + extension = ".webp" + case strings.Contains(extension, "image/gif"): + extension = ".gif" + default: + return fmt.Errorf( + "ValidateAndConvertUpdateProfileRequest: Unsupported image type: %v", extension) + } + var resizedImageBytes []byte + resizedImageBytes, err := resizeAndConvertToWebp( + requestData.NewProfilePic, uint(fes.Params.MaxProfilePicDimensions), extension) + if err != nil { + return fmt.Errorf( + "ValidateAndConvertUpdateProfileRequest: Problem resizing profile picture: %v", err) + } + // Convert the image back into base64 + webpBase64 := base64.StdEncoding.EncodeToString(resizedImageBytes) + requestData.NewProfilePic = "data:image/webp;base64," + webpBase64 + if uint64(len([]byte(requestData.NewProfilePic))) > utxoView.Params.MaxProfilePicLengthBytes { + return errors.Wrap(lib.RuleErrorMaxProfilePicSize, "ValidateAndConvertUpdateProfileRequest") + } + } + + // CreatorBasisPoints > 0 < max, uint64 can't be less than zero + if requestData.NewCreatorBasisPoints > fes.Params.MaxCreatorBasisPoints { + return fmt.Errorf( + "ValidateAndConvertUpdateProfileRequest: Creator percentage must be less than %v percent", + fes.Params.MaxCreatorBasisPoints/100) + } + + // Verify that this username doesn't exist in the mempool. + if len(requestData.NewUsername) > 0 { + + utxoView.GetProfileEntryForUsername([]byte(requestData.NewUsername)) + existingProfile, usernameExists := + utxoView.ProfileUsernameToProfileEntry[lib.MakeUsernameMapKey([]byte(requestData.NewUsername))] + if usernameExists && existingProfile != nil && !existingProfile.IsDeleted() { + // Check that the existing profile does not belong to the profile public key + if utxoView.GetPKIDForPublicKey(profilePublicKey) != + utxoView.GetPKIDForPublicKey(existingProfile.PublicKey) { + return fmt.Errorf( + "ValidateAndConvertUpdateProfileRequest: Username %v already exists", + string(existingProfile.Username)) + } + + } + if !lib.UsernameRegex.Match([]byte(requestData.NewUsername)) { + return errors.Wrap(lib.RuleErrorInvalidUsername, "ValidateAndConvertUpdateProfileRequest") + } + } + + return nil +} + func (fes *APIServer) CompProfileCreation(profilePublicKey []byte, userMetadata *UserMetadata, utxoView *lib.UtxoView) (_additionalFee uint64, _txnHash *lib.BlockHash, _err error) { // Determine if this is a profile creation request and if we need to comp the user for creating the profile. existingProfileEntry := utxoView.GetProfileEntryForPublicKey(profilePublicKey) @@ -620,9 +631,219 @@ func GetBalanceForPublicKeyUsingUtxoView( return totalBalanceNanos, nil } +// SubsidizedUpdateProfileResponse ... +type SubsidizedUpdateProfileResponse struct { + // IncompleteAtomicTransactions is a DeSo transaction of type lib.TxnTypeAtomicTxnsWrapper. + // It contains a metadata field that is a list of the following DeSo transactions + // that are to be executed atomically: + // + // (1) A signed basic transfer to the user who submitted the subsidized update profile request. + // The transferred amount is the exact amount required to pay for the update profile transaction. + // (2) The unsigned requested update profile transaction. + // + // The caller on receipt of this response should sign the update profile + // transaction and then submit the atomic transaction. + IncompleteAtomicTransaction *lib.MsgDeSoTxn +} + // SubsidizedUpdateProfile func (fes *APIServer) SubsidizedUpdateProfile(ww http.ResponseWriter, req *http.Request) { - _AddBadRequestError(ww, "SubsidizedUpdateProfile: Not implemented") + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := UpdateProfileRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Problem parsing request body: %v", err)) + return + } + + // Grab a view (needed for getting global params, etc). + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Error getting utxoView: %v", err)) + return + } + + // Grab subsidization keys. + subsidizationSeedBytes, err := bip39.NewSeedWithErrorChecking(fes.Config.TransactionSubsidizationSeed, "") + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem generating subsidization seed: %v", err)) + return + } + subsidizationPublicKey, subsidizationPrivateKey, _, err := + lib.ComputeKeysFromSeed(subsidizationSeedBytes, 0, fes.Params) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem computing subsidization keys: %v", err)) + return + } + + // Convert the updater and profile public keys to bytes. + var profilePublicKeyBytes, updaterPublicKeyBytes []byte + if requestData.ProfilePublicKeyBase58Check != "" { + profilePublicKeyBytes, _, err = lib.Base58CheckDecode(requestData.ProfilePublicKeyBase58Check) + if err != nil || len(profilePublicKeyBytes) != btcec.PubKeyBytesLenCompressed { + _AddBadRequestError(ww, fmt.Sprintf( + "SubsidizedUpdateProfile: Problem decoding profile public key %s: %v", + requestData.ProfilePublicKeyBase58Check, err)) + return + } + } + if requestData.UpdaterPublicKeyBase58Check != "" { + updaterPublicKeyBytes, _, err = lib.Base58CheckDecode(requestData.UpdaterPublicKeyBase58Check) + if err != nil || len(updaterPublicKeyBytes) != btcec.PubKeyBytesLenCompressed { + _AddBadRequestError(ww, fmt.Sprintf( + "SubsidizedUpdateProfile: Problem decoding updater public key %s: %v", + requestData.UpdaterPublicKeyBase58Check, err)) + return + } + } + + // Grab the profile being updated public key. + profilePublicKey := updaterPublicKeyBytes + if requestData.ProfilePublicKeyBase58Check != "" { + profilePublicKey = profilePublicKeyBytes + } + + // NOTE: We cannot simply copy and paste the existing logic from UpdateProfile + // as some of that logic is dependent on the user's balance being non-zero. Since + // we use this endpoint to subsidize the user's update profile, we instead speculatively + // construct the update profile transaction for the user. + + // (1) Validate and construct the update profile transaction. + var updateProfileTxn *lib.MsgDeSoTxn + + // (1a) Validate the request data. + if err := fes.ValidateAndConvertUpdateProfileRequest(&requestData, profilePublicKey, utxoView); err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem validating request data: %v", err)) + return + } + + // (1b) Compute the transaction fees for this update profile transaction and encode the associated extra data. + additionalOutputs, err := + fes.getTransactionFee(lib.TxnTypeUpdateProfile, updaterPublicKeyBytes, requestData.TransactionFees) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: TransactionFees "+ + "specified in Request body are invalid: %v", err)) + return + } + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("SubsidizedUpdateProfile: Problem encoding ExtraData: %v", err)) + return + } + + // (1c) Determine if a profile creation fee must be paid. + additionalFees := uint64(0) + if existingProfileEntry := utxoView.GetProfileEntryForPublicKey(profilePublicKey); existingProfileEntry == nil { + additionalFees = utxoView.GetCurrentGlobalParamsEntry().CreateProfileFeeNanos + } + + // (1c) Construct the update profile transaction. + updateProfileTxn, _, _, _, err = fes.blockchain.CreateUpdateProfileTxn( + updaterPublicKeyBytes, + profilePublicKeyBytes, + requestData.NewUsername, + requestData.NewDescription, + requestData.NewProfilePic, + requestData.NewCreatorBasisPoints, + requestData.NewStakeMultipleBasisPoints, + requestData.IsHidden, + additionalFees, + extraData, + requestData.MinFeeRateNanosPerKB, + fes.backendServer.GetMempool(), + additionalOutputs, + ) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem creating update profile transaction: %v", err)) + return + } + + // (2) Construct the basic transfer transaction to subsidize the user. + basicTransferTxn := &lib.MsgDeSoTxn{ + TxInputs: []*lib.DeSoInput{}, + TxOutputs: []*lib.DeSoOutput{ + { + AmountNanos: ComputeNecessarySubsidyForTransaction(updateProfileTxn), + PublicKey: updaterPublicKeyBytes, + }, + }, + PublicKey: subsidizationPublicKey.SerializeCompressed(), + TxnMeta: &lib.BasicTransferMetadata{}, + } + _, _, _, _, err = fes.blockchain.AddInputsAndChangeToTransaction( + basicTransferTxn, + utxoView.GetCurrentGlobalParamsEntry().MinimumNetworkFeeNanosPerKB, + fes.backendServer.GetMempool(), + ) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem creating basic transfer transaction: %v", err)) + return + } + + // (3) Wrap the two transactions in an atomic transaction wrapper. + atomicTxnWrapper, totalFees, err := fes.blockchain.CreateAtomicTxnsWrapper( + []*lib.MsgDeSoTxn{basicTransferTxn, updateProfileTxn}, nil) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem constructing atomic transaction wrapper: %v", err)) + return + } + + // (3a) Validate the atomic transaction wrapper has sufficient fees paid. + txnBytes, err := atomicTxnWrapper.ToBytes(true) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem serializing transaction: %v", err)) + return + } + txnSizeBytes := uint64(len(txnBytes)) + if txnSizeBytes != 0 && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB != 0 { + // Check for overflow or minimum network fee not met. + if totalFees != ((totalFees*1000)/1000) || + (totalFees*1000)/uint64(txnSizeBytes) < utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB { + _AddBadRequestError(ww, fmt.Sprint("SubsidizedUpdateProfile: Transactions used to construct"+ + " atomic transaction do not cumulatively pay sufficient network fees to cover wrapper")) + return + } + } + + // (4) Sign the basic transfer transaction within the atomic transaction wrapper. + basicTransferSignature, err := + atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[0].Sign(subsidizationPrivateKey) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem signing basic transfer transaction: %v", err)) + return + } + atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[0].Signature.SetSignature(basicTransferSignature) + + // (5) Return the atomic transaction wrapper to the user. + res := SubsidizedUpdateProfileResponse{ + IncompleteAtomicTransaction: atomicTxnWrapper, + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem encoding response as JSON: %v", err)) + return + } +} + +// ComputeNecessarySubsidyForTransaction is a helper function to find out how much +// a user must be transferred in order to exactly execute a given transaction. +// +// In the balance model era, the total amount of DESO required to execute a transaction +// is equivalent to the sum of the fees paid and the sum of the basic transfers (outputs). +func ComputeNecessarySubsidyForTransaction(txn *lib.MsgDeSoTxn) uint64 { + necessarySubsidy := txn.TxnFeeNanos + for _, txOutput := range txn.TxOutputs { + necessarySubsidy += txOutput.AmountNanos + } + return necessarySubsidy } // ExchangeBitcoinRequest ... From 75737909801404d70b7c1e52169442f3c0f2dde1 Mon Sep 17 00:00:00 2001 From: Jon Pollock <135658176+poolcoke@users.noreply.github.com> Date: Tue, 9 Apr 2024 11:46:50 -0700 Subject: [PATCH 64/84] Atomic Transaction Support for Backend (#560) --- routes/atomic_txns.go | 106 ++++++++++++++++++++++++++++++++++++++++++ routes/server.go | 10 ++++ 2 files changed, 116 insertions(+) create mode 100644 routes/atomic_txns.go diff --git a/routes/atomic_txns.go b/routes/atomic_txns.go new file mode 100644 index 00000000..72b94991 --- /dev/null +++ b/routes/atomic_txns.go @@ -0,0 +1,106 @@ +package routes + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "github.com/deso-protocol/core/lib" + "io" + "net/http" +) + +type CreateAtomicTxnsWrapperRequest struct { + Transactions []*lib.MsgDeSoTxn + ExtraData map[string]string +} + +type CreateAtomicTxnsWrapperResponse struct { + // TransactionsWrapped as a helpful sanity check for the caller of the + // CreateAtomicTxnsWrapper endpoint. That being said, the caller should + // also sanity check that the returned wrapper transaction has the atomic + // transactions ordered correctly. + TransactionsWrapped uint64 `safeForLogging:"true"` + + // TotalFeeNanos represents the total fees paid cumulatively by all + // wrapper atomic transactions and is consistent with the + // returned Transaction.TxnFeeNanos field. + TotalFeeNanos uint64 + Transaction *lib.MsgDeSoTxn + TransactionHex string +} + +func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := CreateAtomicTxnsWrapperRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Error parsing request body: %v", err)) + return + } + + // Grab a view (needed for getting global params, etc). + utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Error getting utxoView: %v", err)) + return + } + + // Validate the request data. + if len(requestData.Transactions) == 0 { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: must have at least one transaction "+ + "in Transactions")) + return + } + + // Encode the ExtraData map. + extraData, err := EncodeExtraDataMap(requestData.ExtraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem encoding ExtraData: %v", err)) + return + } + + // Construct the atomic transactions wrapper transaction type. + txn, totalFees, err := fes.blockchain.CreateAtomicTxnsWrapper(requestData.Transactions, extraData) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem constructing transaction: %v", err)) + return + } + + // Serialize the transaction. + txnBytes, err := txn.ToBytes(true) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem serializing transaction: %v", err)) + return + } + txnSizeBytes := uint64(len(txnBytes)) + + // Validate that: + // (1) The resulting transaction is not over the size limit of an atomic transaction. + // (2) The resulting wrapper transactions have sufficient fees to cover the wrapper. + if txnSizeBytes > utxoView.GetCurrentGlobalParamsEntry().MaxTxnSizeBytesPoS { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Resulting wrapper transaction too large")) + return + } + if txnSizeBytes != 0 && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB != 0 { + // Check for overflow or minimum network fee not met. + if totalFees != ((totalFees*1000)/1000) || + (totalFees*1000)/uint64(txnSizeBytes) < utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB { + _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Transactions used to construct"+ + " atomic transaction do not cumulatively pay sufficient network fees to cover wrapper")) + return + } + } + + // Construct a response. + res := CreateAtomicTxnsWrapperResponse{ + TransactionsWrapped: uint64(len(txn.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns)), + TotalFeeNanos: totalFees, + Transaction: txn, + TransactionHex: hex.EncodeToString(txnBytes), + } + + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, + fmt.Sprintf("CreateAtomicTxnsWrapper: Problem serializing object to JSON: %v", err)) + return + } +} diff --git a/routes/server.go b/routes/server.go index 628e08c4..8c84afde 100644 --- a/routes/server.go +++ b/routes/server.go @@ -331,6 +331,9 @@ const ( RoutePathCoinUnlock = "/api/v0/coin-unlock" RoutePathLockupYieldCurvePoints = "/api/v0/lockup-yield-curve-points" RoutePathLockedBalanceEntries = "/api/v0/locked-balance-entries" + + // atomic_txns.go + RoutePathCreateAtomicTxnsWrapper = "/api/v0/create-atomic-txns-wrapper" ) // APIServer provides the interface between the blockchain and things like the @@ -1419,6 +1422,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.LockedBalanceEntries, PublicAccess, }, + { + "CreateAtomicTxnsWrapper", + []string{"POST", "OPTIONS"}, + RoutePathCreateAtomicTxnsWrapper, + fes.CreateAtomicTxnsWrapper, + PublicAccess, + }, // Jumio Routes { "JumioBegin", From 61ea63809d1795d95b32973ff4eb0db4feb418c9 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:48:41 -0400 Subject: [PATCH 65/84] Update usage of CreateAtomicTxnsWrapper (#581) --- routes/atomic_txns.go | 7 ++++--- scripts/tools/toolslib/offline_basic_transfer.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/routes/atomic_txns.go b/routes/atomic_txns.go index 72b94991..10990def 100644 --- a/routes/atomic_txns.go +++ b/routes/atomic_txns.go @@ -59,7 +59,8 @@ func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http. } // Construct the atomic transactions wrapper transaction type. - txn, totalFees, err := fes.blockchain.CreateAtomicTxnsWrapper(requestData.Transactions, extraData) + txn, totalFees, err := fes.blockchain.CreateAtomicTxnsWrapper( + requestData.Transactions, extraData, fes.backendServer.GetMempool()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateAtomicTxnsWrapper: Problem constructing transaction: %v", err)) return @@ -80,10 +81,10 @@ func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http. _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Resulting wrapper transaction too large")) return } - if txnSizeBytes != 0 && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB != 0 { + if txnSizeBytes != 0 && utxoView.GetCurrentGlobalParamsEntry().MinimumNetworkFeeNanosPerKB != 0 { // Check for overflow or minimum network fee not met. if totalFees != ((totalFees*1000)/1000) || - (totalFees*1000)/uint64(txnSizeBytes) < utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB { + (totalFees*1000)/uint64(txnSizeBytes) < utxoView.GetCurrentGlobalParamsEntry().MinimumNetworkFeeNanosPerKB { _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Transactions used to construct"+ " atomic transaction do not cumulatively pay sufficient network fees to cover wrapper")) return diff --git a/scripts/tools/toolslib/offline_basic_transfer.go b/scripts/tools/toolslib/offline_basic_transfer.go index f24f6895..2bbe6c36 100644 --- a/scripts/tools/toolslib/offline_basic_transfer.go +++ b/scripts/tools/toolslib/offline_basic_transfer.go @@ -78,7 +78,7 @@ func _computeFee(txn *lib.MsgDeSoTxn, feeRateNanosPerKB uint64) (*lib.MsgDeSoTxn if (uint64(txnWithSigLen)*feeRateNanosPerKB)%1000 != 0 { feeAmountNanos++ } - txn.TxnFeeNanos = uint64(feeAmountNanos) + lib.UpdateTxnFee(txn, uint64(feeAmountNanos)) } return txn, nil } From 001661ca26c33d2c62a36672a4b46c0d85c4ca3c Mon Sep 17 00:00:00 2001 From: Jon Pollock <135658176+poolcoke@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:35:35 -0700 Subject: [PATCH 66/84] Add a Preceding Transaction Field to Transaction Endpoints. (#570) * Simple CreateAtomicTxnsWrapper scaffolding. * Update method on CreateAtomicTxnsWrapper. * Use lib.GetAugmentedUniversalViewWithAdditionalTransactions for UpdateProfile. * Use MaxTxnSizeBytesPoS for atomic transaction construction. * Use updated lib.GetAugmentedUniversalViewWithAdditionalTransactions parameters. * Gate preceding transactions middleware on POST requests. * Use anonymous struct to simplify preceding transaction middleware. * Update stateful transaction endpoints to use GetAugmentedUniversalViewWithAdditionalTransactions. * Simple CreateAtomicTxnsWrapper scaffolding. * Update method on CreateAtomicTxnsWrapper. * Use MaxTxnSizeBytesPoS for atomic transaction construction. * Fix MaxTxnSizeBytes bug --------- Co-authored-by: diamondhands Co-authored-by: Lazy Nina <81658138+lazynina@users.noreply.github.com> --- cmd/run.go | 7 ++++ config/config.go | 6 ++++ routes/access_group.go | 14 ++++++-- routes/admin_transaction.go | 26 +++++++++++--- routes/admin_user.go | 4 +-- routes/atomic_txns.go | 1 + routes/hot_feed.go | 4 +-- routes/nft.go | 49 +++++++++++++++++++++---- routes/server.go | 46 ++++++++++++++++++++++++ routes/stake.go | 14 ++++++-- routes/transaction.go | 72 ++++++++++++++++++++++++++++++------- 11 files changed, 211 insertions(+), 32 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 02486a57..9c62b2bd 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -112,6 +112,13 @@ func init() { runCmd.PersistentFlags().String("amplitude-key", "", "Client-side amplitude key for instrumenting user behavior.") runCmd.PersistentFlags().String("amplitude-domain", "api.amplitude.com", "Client-side amplitude API Endpoint.") + // Transactions + runCmd.PersistentFlags().Int("max-optional-preceding-transactions", 0, + "If set, enables certain transaction construction "+ + "endpoints to accept transactions that should be connected "+ + "before constructing the specified transaction. "+ + "Setting this flag can aid in workflows that deal with atomic transaction construction.") + // User Interface runCmd.PersistentFlags().String("support-email", "", "Show a support email to users of this node") runCmd.PersistentFlags().Bool("show-processing-spinners", false, diff --git a/config/config.go b/config/config.go index 81b9b47a..a5e566ec 100644 --- a/config/config.go +++ b/config/config.go @@ -46,6 +46,9 @@ type Config struct { // Analytics AmplitudeKey string + // Transactions + MaxOptionalPrecedingTransactions int + // Images GCPCredentialsPath string GCPBucketName string @@ -148,6 +151,9 @@ func LoadConfig(coreConfig *coreCmd.Config) *Config { // Analytics config.AmplitudeKey = viper.GetString("amplitude-key") + // Transactions + config.MaxOptionalPrecedingTransactions = viper.GetInt("max-optional-preceding-transactions") + // Images config.GCPCredentialsPath = viper.GetString("gcp-credentials-path") config.GCPBucketName = viper.GetString("gcp-bucket-name") diff --git a/routes/access_group.go b/routes/access_group.go index 6a5b7278..3da7973b 100644 --- a/routes/access_group.go +++ b/routes/access_group.go @@ -27,6 +27,8 @@ type CreateAccessGroupRequest struct { TransactionFees []TransactionFee `safeForLogging:"true"` // ExtraData is an arbitrary key value map ExtraData map[string]string + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // struct to construct the response to create an access group. @@ -85,7 +87,10 @@ func (fes *APIServer) accessGroupHandler( "public key %s: %v", accessGroupPkBytes, err) } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { return fmt.Errorf("error getting view: %v", err) } @@ -227,6 +232,8 @@ type AddAccessGroupMembersRequest struct { TransactionFees []TransactionFee `safeForLogging:"true"` // ExtraData is an arbitrary key value map ExtraData map[string]string + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // struct to construct the response to create an access group. @@ -274,7 +281,10 @@ func (fes *APIServer) accessGroupMemberHandler( "public key and access group key name %s: %v", requestData.AccessGroupKeyName, err) } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { return fmt.Errorf("error getting utxo view: %v", err) } diff --git a/routes/admin_transaction.go b/routes/admin_transaction.go index 4f6bbceb..9cd7e11d 100644 --- a/routes/admin_transaction.go +++ b/routes/admin_transaction.go @@ -157,6 +157,8 @@ type UpdateGlobalParamsRequest struct { // Whether or not we should broadcast the transaction after constructing // it. This will also validate the transaction if it's set. Broadcast bool `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // UpdateGlobalParamsResponse ... @@ -192,7 +194,10 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque } // Get a utxoView. - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateGlobalParams: Error constucting utxoView: %v", err)) return @@ -316,6 +321,8 @@ type SwapIdentityRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // SwapIdentityResponse ... @@ -327,7 +334,13 @@ type SwapIdentityResponse struct { TransactionHex string } -func (fes *APIServer) getPublicKeyFromUsernameOrPublicKeyString(usernameOrPublicKey string) ([]byte, error) { +func (fes *APIServer) getPublicKeyFromUsernameOrPublicKeyString( + usernameOrPublicKey string, + optionalPrecedingTransactions []*lib.MsgDeSoTxn, +) ( + []byte, + error, +) { if (strings.HasPrefix(usernameOrPublicKey, fes.PublicKeyBase58Prefix)) && len(usernameOrPublicKey) >= btcec.PubKeyBytesLenCompressed { @@ -341,7 +354,10 @@ func (fes *APIServer) getPublicKeyFromUsernameOrPublicKeyString(usernameOrPublic } // Otherwise, parse the string as a username - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + optionalPrecedingTransactions, + ) if err != nil { return nil, errors.Wrap(fmt.Errorf("getPublicKeyFromUsernameOrPublicKeyString: Error generating "+ "view to verify username: %v", err), "") @@ -382,13 +398,13 @@ func (fes *APIServer) SwapIdentity(ww http.ResponseWriter, req *http.Request) { } fromPublicKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString( - requestData.FromUsernameOrPublicKeyBase58Check) + requestData.FromUsernameOrPublicKeyBase58Check, requestData.OptionalPrecedingTransactions) if err != nil { _AddBadRequestError(ww, err.Error()) return } toPublicKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString( - requestData.ToUsernameOrPublicKeyBase58Check) + requestData.ToUsernameOrPublicKeyBase58Check, requestData.OptionalPrecedingTransactions) if err != nil { _AddBadRequestError(ww, err.Error()) return diff --git a/routes/admin_user.go b/routes/admin_user.go index f6948806..bc9eb092 100644 --- a/routes/admin_user.go +++ b/routes/admin_user.go @@ -675,7 +675,7 @@ func (fes *APIServer) AdminGrantVerificationBadge(ww http.ResponseWriter, req *h } // Verify the username has an underlying profile - pubKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString(usernameToVerify) + pubKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString(usernameToVerify, nil) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AdminGrantVerificationBadge: Username %s has no associated underlying publickey.", usernameToVerify)) @@ -781,7 +781,7 @@ func (fes *APIServer) AdminRemoveVerificationBadge(ww http.ResponseWriter, req * } // Verify the username has an underlying profile - pubKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString(usernameToRemove) + pubKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString(usernameToRemove, nil) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AdminRemoveVerificationBadge: Username has no associated underlying publickey")) return diff --git a/routes/atomic_txns.go b/routes/atomic_txns.go index 10990def..86539f8c 100644 --- a/routes/atomic_txns.go +++ b/routes/atomic_txns.go @@ -81,6 +81,7 @@ func (fes *APIServer) CreateAtomicTxnsWrapper(ww http.ResponseWriter, req *http. _AddBadRequestError(ww, fmt.Sprint("CreateAtomicTxnsWrapper: Resulting wrapper transaction too large")) return } + if txnSizeBytes != 0 && utxoView.GetCurrentGlobalParamsEntry().MinimumNetworkFeeNanosPerKB != 0 { // Check for overflow or minimum network fee not met. if totalFees != ((totalFees*1000)/1000) || diff --git a/routes/hot_feed.go b/routes/hot_feed.go index 9c1b127a..cf9ce469 100644 --- a/routes/hot_feed.go +++ b/routes/hot_feed.go @@ -1325,7 +1325,7 @@ func (fes *APIServer) AdminUpdateHotFeedUserMultiplier(ww http.ResponseWriter, r } // Verify the username has an underlying profile. - pubKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString(requestData.Username) + pubKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString(requestData.Username, nil) if err != nil { _AddBadRequestError(ww, fmt.Sprintf( @@ -1394,7 +1394,7 @@ func (fes *APIServer) AdminGetHotFeedUserMultiplier(ww http.ResponseWriter, req } // Verify the username has an underlying profile. - pubKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString(requestData.Username) + pubKey, err := fes.getPublicKeyFromUsernameOrPublicKeyString(requestData.Username, nil) if err != nil { _AddBadRequestError(ww, fmt.Sprintf( diff --git a/routes/nft.go b/routes/nft.go index 65fbe757..07cedbd2 100644 --- a/routes/nft.go +++ b/routes/nft.go @@ -89,6 +89,8 @@ type CreateNFTRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type CreateNFTResponse struct { @@ -110,7 +112,10 @@ func (fes *APIServer) CreateNFT(ww http.ResponseWriter, req *http.Request) { } // Grab a view (needed for getting global params, etc). - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateNFT: Error getting utxoView: %v", err)) return @@ -306,6 +311,8 @@ type UpdateNFTRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type UpdateNFTResponse struct { @@ -327,7 +334,10 @@ func (fes *APIServer) UpdateNFT(ww http.ResponseWriter, req *http.Request) { return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateNFT: Error getting utxoView: %v", err)) return @@ -454,6 +464,8 @@ type CreateNFTBidRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type CreateNFTBidResponse struct { @@ -477,7 +489,10 @@ func (fes *APIServer) CreateNFTBid(ww http.ResponseWriter, req *http.Request) { return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateNFTBid: Error getting utxoView: %v", err)) return @@ -615,6 +630,8 @@ type AcceptNFTBidRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type AcceptNFTBidResponse struct { @@ -638,7 +655,10 @@ func (fes *APIServer) AcceptNFTBid(ww http.ResponseWriter, req *http.Request) { return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AcceptNFTBid: Error getting utxoView: %v", err)) return @@ -1531,6 +1551,8 @@ type TransferNFTRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type TransferNFTResponse struct { @@ -1554,7 +1576,10 @@ func (fes *APIServer) TransferNFT(ww http.ResponseWriter, req *http.Request) { return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferNFT: Error getting utxoView: %v", err)) return @@ -1693,6 +1718,8 @@ type AcceptNFTTransferRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type AcceptNFTTransferResponse struct { @@ -1715,7 +1742,10 @@ func (fes *APIServer) AcceptNFTTransfer(ww http.ResponseWriter, req *http.Reques return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("AcceptNFTTransfer: Error getting utxoView: %v", err)) return @@ -1832,6 +1862,8 @@ type BurnNFTRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type BurnNFTResponse struct { @@ -1854,7 +1886,10 @@ func (fes *APIServer) BurnNFT(ww http.ResponseWriter, req *http.Request) { return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("BurnNFT: Error getting utxoView: %v", err)) return diff --git a/routes/server.go b/routes/server.go index 8c84afde..e27ab69d 100644 --- a/routes/server.go +++ b/routes/server.go @@ -2344,6 +2344,7 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { // If the route is not "PublicAccess" we wrap it in a function to check that the caller // has the correct permissions before calling its handler. + handler = CheckPrecedingTransactions(handler, fes.Config.MaxOptionalPrecedingTransactions) if route.AccessLevel != PublicAccess { handler = fes.CheckAdminPublicKey(handler, route.AccessLevel) } @@ -2369,6 +2370,51 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { return router } +// CheckPrecedingTransactions is middleware that ensures any request body with the "OptionalPrecedingTransactions" +// field set is limited in how many transactions are being sent to the server. +// +// By default, the maximum number that can be sent to the server is zero. The OptionalPrecedingTransactions field +// is used in constructing UtxoViews for atomic transaction workflows. +func CheckPrecedingTransactions(inner http.Handler, precedingTransactionsLimit int) http.Handler { + return http.HandlerFunc(func(ww http.ResponseWriter, rr *http.Request) { + // If the request is NOT a POST request, skip this middleware as the request has no relevant payload. + if rr.Method != "POST" { + inner.ServeHTTP(ww, rr) + return + } + + // Read and replace the request body. + data, err := io.ReadAll(rr.Body) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CheckPrecedingTransactions: %v", err)) + return + } + rr.Body.Close() + rr.Body = io.NopCloser(bytes.NewReader(data)) + + // Unmarshal the request such that we snag the OptionalPrecedingTransactions field from relevant endpoints. + var optionalPrecedingTransactionsStruct struct { + OptionalPrecedingTransactions []*lib.MsgDeSoTxn + } + if err := json.Unmarshal(data, &optionalPrecedingTransactionsStruct); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("CheckPrecedingTransactions failed to unmarshal json: %v", err)) + return + } + + // Validate the number of transactions being sent to the endpoint. + if optionalPrecedingTransactionsStruct.OptionalPrecedingTransactions != nil && + len(optionalPrecedingTransactionsStruct.OptionalPrecedingTransactions) > precedingTransactionsLimit { + _AddBadRequestError(ww, + fmt.Sprintf("CheckPrecedingTransactions: too many optional preceding transactions: %d > %d", + len(optionalPrecedingTransactionsStruct.OptionalPrecedingTransactions), precedingTransactionsLimit)) + return + } + + // Pass the request down to the next handler. + inner.ServeHTTP(ww, rr) + }) +} + // Logger ... func Logger(inner http.Handler, name string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/routes/stake.go b/routes/stake.go index 891d9c74..734e4af7 100644 --- a/routes/stake.go +++ b/routes/stake.go @@ -55,6 +55,8 @@ type StakeRequest struct { ExtraData map[string]string `safeForLogging:"true"` MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type UnstakeRequest struct { @@ -64,6 +66,8 @@ type UnstakeRequest struct { ExtraData map[string]string `safeForLogging:"true"` MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } type UnlockStakeRequest struct { @@ -159,7 +163,10 @@ func (fes *APIServer) CreateStakeTxn(ww http.ResponseWriter, req *http.Request) return } stakeAmountNanosUint64 := requestData.StakeAmountNanos.Uint64() - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateStakeTxn: Problem fetching utxoView: %v", err)) return @@ -273,7 +280,10 @@ func (fes *APIServer) CreateUnstakeTxn(ww http.ResponseWriter, req *http.Request _AddBadRequestError(ww, fmt.Sprint("CreateUnstakeTxn: UnstakeAmountNanos must be a uint64")) return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("CreateUnstakeTxn: Problem fetching utxoView: %v", err)) return diff --git a/routes/transaction.go b/routes/transaction.go index 301c4339..798fe953 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -238,6 +238,8 @@ type UpdateProfileRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // UpdateProfileResponse ... @@ -282,8 +284,10 @@ func (fes *APIServer) UpdateProfile(ww http.ResponseWriter, req *http.Request) { _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Problem with getUserMetadataFromGlobalState: %v", err)) return } - - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Error fetching mempool view: %v", err)) return @@ -1022,6 +1026,8 @@ type SendDeSoRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // SendDeSoResponse ... @@ -1062,7 +1068,10 @@ func (fes *APIServer) SendDeSo(ww http.ResponseWriter, req *http.Request) { } else { // TODO(performance): This is inefficient because it loads all mempool // transactions. - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SendDeSo: Error generating "+ "view to verify username: %v", err)) @@ -1321,6 +1330,8 @@ type SubmitPostRequest struct { // If true, the post will be "frozen", i.e. no longer editable. IsFrozen bool `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // SubmitPostResponse ... @@ -1410,8 +1421,10 @@ func (fes *APIServer) SubmitPost(ww http.ResponseWriter, req *http.Request) { postHashToModify = postHashToModifyBytes } - var utxoView *lib.UtxoView - utxoView, err = fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SubmitPost: Error getting utxoView")) return @@ -1732,6 +1745,8 @@ type BuyOrSellCreatorCoinRequest struct { BitCloutToSellNanos uint64 `safeForLogging:"true"` // Deprecated BitCloutToAddNanos uint64 `safeForLogging:"true"` // Deprecated MinBitCloutExpectedNanos uint64 `safeForLogging:"true"` // Deprecated + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // BuyOrSellCreatorCoinResponse ... @@ -1846,7 +1861,10 @@ func (fes *APIServer) BuyOrSellCreatorCoin(ww http.ResponseWriter, req *http.Req // Add node source to txn metadata fes.AddNodeSourceToTxnMetadata(txn) - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUtxoViewForPublicKey(updaterPublicKeyBytes, txn) + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("BuyOrSellCreatorCoin: Problem computing view for transaction: %v", err)) return @@ -2002,6 +2020,8 @@ type TransferCreatorCoinRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // TransferCreatorCoinResponse ... @@ -2058,7 +2078,10 @@ func (fes *APIServer) TransferCreatorCoin(ww http.ResponseWriter, req *http.Requ var receiverPublicKeyBytes []byte if uint64(len(requestData.ReceiverUsernameOrPublicKeyBase58Check)) <= fes.Params.MaxUsernameLengthBytes { // The receiver string is too short to be a public key. Lookup the username. - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferCreatorCoin: Problem fetching utxoView: %v", err)) return @@ -2362,6 +2385,8 @@ type DAOCoinRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // DAOCoinResponse ... @@ -2400,7 +2425,10 @@ func (fes *APIServer) DAOCoin(ww http.ResponseWriter, req *http.Request) { return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("DAOCoin: Problem computing view: %v", err)) return @@ -2538,6 +2566,8 @@ type TransferDAOCoinRequest struct { // No need to specify ProfileEntryResponse in each TransactionFee TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // TransferDAOCoinResponse ... @@ -2567,7 +2597,10 @@ func (fes *APIServer) TransferDAOCoin(ww http.ResponseWriter, req *http.Request) return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("TransferDAOCoin: Problem fetching utxoView: %v", err)) return @@ -2707,6 +2740,8 @@ type DAOCoinLimitOrderCreationRequest struct { MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // CreateDAOCoinLimitOrder Constructs a transaction that creates a DAO coin limit order for the specified @@ -2795,7 +2830,10 @@ func (fes *APIServer) CreateDAOCoinLimitOrder(ww http.ResponseWriter, req *http. return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("CreateDAOCoinLimitOrder: problem fetching utxoView: %v", err)) return @@ -2897,6 +2935,8 @@ type DAOCoinMarketOrderCreationRequest struct { MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } func (fes *APIServer) CreateDAOCoinMarketOrder(ww http.ResponseWriter, req *http.Request) { @@ -2973,7 +3013,10 @@ func (fes *APIServer) CreateDAOCoinMarketOrder(ww http.ResponseWriter, req *http return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("CreateDAOCoinMarketOrder: problem fetching utxoView: %v", err)) return @@ -3073,6 +3116,8 @@ type DAOCoinLimitOrderWithCancelOrderIDRequest struct { MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` TransactionFees []TransactionFee `safeForLogging:"true"` + + OptionalPrecedingTransactions []*lib.MsgDeSoTxn `safeForLogging:"true"` } // CancelDAOCoinLimitOrder Constructs a transaction that cancels an existing DAO coin limit order with the specified @@ -3097,7 +3142,10 @@ func (fes *APIServer) CancelDAOCoinLimitOrder(ww http.ResponseWriter, req *http. return } - utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() + utxoView, err := lib.GetAugmentedUniversalViewWithAdditionalTransactions( + fes.backendServer.GetMempool(), + requestData.OptionalPrecedingTransactions, + ) if err != nil { _AddInternalServerError(ww, fmt.Sprintf("CancelDAOCoinLimitOrder: problem fetching utxoView: %v", err)) return From d2134ea4d91e5ace02dcac55efe78fbe41c35555 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:14:41 -0400 Subject: [PATCH 67/84] Add all new global params attributes to update global params txn construction endpoint (#583) --- routes/admin_transaction.go | 112 ++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/routes/admin_transaction.go b/routes/admin_transaction.go index 9cd7e11d..dc7c634f 100644 --- a/routes/admin_transaction.go +++ b/routes/admin_transaction.go @@ -130,6 +130,14 @@ type UpdateGlobalParamsRequest struct { // are included when generating a new Proof-of-Stake validator set. ValidatorSetMaxNumValidators uint64 `safeForLogging:"true"` + // StakingRewardsMaxNumStakes is the maximum number of stakes that + // are eligible to receive rewards in the end of epoch hook. + StakingRewardsMaxNumStakes uint64 `safeForLogging:"true"` + + // StakingRewardsAPYBasisPoints is the annual percentage yield that + // is used to compute end-of-epoch staking rewards. + StakingRewardsAPYBasisPoints uint64 `safeForLogging:"true"` + // EpochDurationNumBlocks is the number of blocks included in one epoch. EpochDurationNumBlocks uint64 `safeForLogging:"true"` @@ -138,6 +146,45 @@ type UpdateGlobalParamsRequest struct { // blocks) before they are jailed. JailInactiveValidatorGracePeriodEpochs uint64 `safeForLogging:"true"` + // MaximumVestedIntersectionsPerLockupTransaction is the maximum number + // of intersections that can be vested per lockup transaction. + MaximumVestedIntersectionsPerLockupTransaction int `safeForLogging:"true"` + + // FeeBucketGrowthRateBasisPoints is the growth rate in basis points of + // fee buckets for the mempool's transaction register. + FeeBucketGrowthRateBasisPoints uint64 `safeForLogging:"true"` + + // BlockTimestampDriftNanoSecs is the maximum number of nanoseconds from the current timestamp that + // we will allow a PoS block to be submitted. + BlockTimestampDriftNanoSecs int64 `safeForLogging:"true"` + + // MempoolMaxSizeBytes is the maximum size of the mempool in bytes. + MempoolMaxSizeBytes uint64 `safeForLogging:"true"` + + // MempoolFeeEstimatorNumMempoolBlocks is the number of possible future blocks to a txn may be placed + // into when consider when estimating the fee for a new txn. + MempoolFeeEstimatorNumMempoolBlocks uint64 + + // MempoolFeeEstimatorNumPastBlocks is the number of past blocks to reference txn fees from when estimating + // the fee for a new txn. + MempoolFeeEstimatorNumPastBlocks uint64 + + // MaxBlockSizeBytesPoS is the maximum size of a block in bytes. + MaxBlockSizeBytesPoS uint64 + + // SoftMaxBlockSizeBytesPoS is the ideal steady state size of a block in bytes. + // This value will be used to control size of block production and congestion in fee estimation. + SoftMaxBlockSizeBytesPoS uint64 + + // MaxTxnSizeBytesPoS is the maximum size of a transaction in bytes allowed. + MaxTxnSizeBytesPoS uint64 + + // BlockProductionIntervalMillisecondsPoS is the time in milliseconds to produce blocks. + BlockProductionIntervalMillisecondsPoS uint64 + + // TimeoutIntervalMillisecondsPoS is the time in milliseconds to wait before timing out a view. + TimeoutIntervalMillisecondsPoS uint64 + MinFeeRateNanosPerKB uint64 `safeForLogging:"true"` // No need to specify ProfileEntryResponse in each TransactionFee @@ -256,6 +303,16 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque extraData[lib.ValidatorSetMaxNumValidatorsKey] = lib.UintToBuf(requestData.ValidatorSetMaxNumValidators) } + if requestData.StakingRewardsMaxNumStakes > 0 && + requestData.StakingRewardsMaxNumStakes != globalParamsEntry.StakingRewardsMaxNumStakes { + extraData[lib.StakingRewardsMaxNumStakesKey] = lib.UintToBuf(requestData.StakingRewardsMaxNumStakes) + } + + if requestData.StakingRewardsAPYBasisPoints > 0 && + requestData.StakingRewardsAPYBasisPoints != globalParamsEntry.StakingRewardsAPYBasisPoints { + extraData[lib.StakingRewardsAPYBasisPointsKey] = lib.UintToBuf(requestData.StakingRewardsAPYBasisPoints) + } + if requestData.EpochDurationNumBlocks > 0 && requestData.EpochDurationNumBlocks != globalParamsEntry.EpochDurationNumBlocks { extraData[lib.EpochDurationNumBlocksKey] = lib.UintToBuf(requestData.EpochDurationNumBlocks) @@ -266,6 +323,61 @@ func (fes *APIServer) UpdateGlobalParams(ww http.ResponseWriter, req *http.Reque extraData[lib.JailInactiveValidatorGracePeriodEpochsKey] = lib.UintToBuf(requestData.JailInactiveValidatorGracePeriodEpochs) } + if requestData.MaximumVestedIntersectionsPerLockupTransaction > 0 && + requestData.MaximumVestedIntersectionsPerLockupTransaction != globalParamsEntry.MaximumVestedIntersectionsPerLockupTransaction { + extraData[lib.MaximumVestedIntersectionsPerLockupTransactionKey] = lib.IntToBuf(int64(requestData.MaximumVestedIntersectionsPerLockupTransaction)) + } + + if requestData.FeeBucketGrowthRateBasisPoints > 0 && + requestData.FeeBucketGrowthRateBasisPoints != globalParamsEntry.FeeBucketGrowthRateBasisPoints { + extraData[lib.FeeBucketGrowthRateBasisPointsKey] = lib.UintToBuf(requestData.FeeBucketGrowthRateBasisPoints) + } + + if requestData.BlockTimestampDriftNanoSecs > 0 && + requestData.BlockTimestampDriftNanoSecs != globalParamsEntry.BlockTimestampDriftNanoSecs { + extraData[lib.BlockTimestampDriftNanoSecsKey] = lib.IntToBuf(requestData.BlockTimestampDriftNanoSecs) + } + + if requestData.MempoolMaxSizeBytes > 0 && + requestData.MempoolMaxSizeBytes != globalParamsEntry.MempoolMaxSizeBytes { + extraData[lib.MempoolMaxSizeBytesKey] = lib.UintToBuf(requestData.MempoolMaxSizeBytes) + } + + if requestData.MempoolFeeEstimatorNumMempoolBlocks > 0 && + requestData.MempoolFeeEstimatorNumMempoolBlocks != globalParamsEntry.MempoolFeeEstimatorNumMempoolBlocks { + extraData[lib.MempoolFeeEstimatorNumMempoolBlocksKey] = lib.UintToBuf(requestData.MempoolFeeEstimatorNumMempoolBlocks) + } + + if requestData.MempoolFeeEstimatorNumPastBlocks > 0 && + requestData.MempoolFeeEstimatorNumPastBlocks != globalParamsEntry.MempoolFeeEstimatorNumPastBlocks { + extraData[lib.MempoolFeeEstimatorNumPastBlocksKey] = lib.UintToBuf(requestData.MempoolFeeEstimatorNumPastBlocks) + } + + if requestData.MaxBlockSizeBytesPoS > 0 && + requestData.MaxBlockSizeBytesPoS != globalParamsEntry.MaxBlockSizeBytesPoS { + extraData[lib.MaxBlockSizeBytesPoSKey] = lib.UintToBuf(requestData.MaxBlockSizeBytesPoS) + } + + if requestData.SoftMaxBlockSizeBytesPoS > 0 && + requestData.SoftMaxBlockSizeBytesPoS != globalParamsEntry.SoftMaxBlockSizeBytesPoS { + extraData[lib.SoftMaxBlockSizeBytesPoSKey] = lib.UintToBuf(requestData.SoftMaxBlockSizeBytesPoS) + } + + if requestData.MaxTxnSizeBytesPoS > 0 && + requestData.MaxTxnSizeBytesPoS != globalParamsEntry.MaxTxnSizeBytesPoS { + extraData[lib.MaxTxnSizeBytesPoSKey] = lib.UintToBuf(requestData.MaxTxnSizeBytesPoS) + } + + if requestData.BlockProductionIntervalMillisecondsPoS > 0 && + requestData.BlockProductionIntervalMillisecondsPoS != globalParamsEntry.BlockProductionIntervalMillisecondsPoS { + extraData[lib.BlockProductionIntervalPoSKey] = lib.UintToBuf(requestData.BlockProductionIntervalMillisecondsPoS) + } + + if requestData.TimeoutIntervalMillisecondsPoS > 0 && + requestData.TimeoutIntervalMillisecondsPoS != globalParamsEntry.TimeoutIntervalMillisecondsPoS { + extraData[lib.TimeoutIntervalPoSKey] = lib.UintToBuf(requestData.TimeoutIntervalMillisecondsPoS) + } + // Try and create the update txn for the user. txn, totalInput, changeAmount, fees, err := fes.blockchain.CreateUpdateGlobalParamsTxn( updaterPkBytes, From 911df1c9bb5e3d23172b113410a0209befa13911 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Tue, 9 Apr 2024 16:32:29 -0400 Subject: [PATCH 68/84] Trigger CI From 9aa87a8ae689004d69f1514b4f6d506eecb798cc Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:01:58 -0400 Subject: [PATCH 69/84] Add get committed tip info endpoint (#582) --- routes/exchange_test.go | 2 +- routes/server.go | 7 +++++++ routes/transaction.go | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/routes/exchange_test.go b/routes/exchange_test.go index 9f0d1674..57872a68 100644 --- a/routes/exchange_test.go +++ b/routes/exchange_test.go @@ -138,7 +138,7 @@ func NewLowDifficultyBlockchainWithParams(t *testing.T, params *lib.DeSoParams) // Temporarily modify the seed balances to make a specific public // key have some DeSo chain, err := lib.NewBlockchain([]string{blockSignerPk}, 0, 0, - ¶msCopy, timesource, db, nil, nil, nil, false) + ¶msCopy, timesource, db, nil, nil, nil, false, nil) if err != nil { log.Fatal(err) } diff --git a/routes/server.go b/routes/server.go index e27ab69d..bcdcdc69 100644 --- a/routes/server.go +++ b/routes/server.go @@ -1035,6 +1035,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.GetTxnConstructionParams, PublicAccess, }, + { + "GetCommittedTipBlockInfo", + []string{"GET"}, + lib.RoutePathGetCommittedTipBlockInfo, + fes.GetCommittedTipBlockInfo, + PublicAccess, + }, { "GetNotifications", []string{"POST", "OPTIONS"}, diff --git a/routes/transaction.go b/routes/transaction.go index 798fe953..403a4a15 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -4346,3 +4346,23 @@ func (fes *APIServer) GetTxnConstructionParams(ww http.ResponseWriter, req *http return } } + +func (fes *APIServer) GetCommittedTipBlockInfo(ww http.ResponseWriter, req *http.Request) { + // Get the block tip from the blockchain. + fes.backendServer.GetBlockchain().ChainLock.RLock() + blockTip, idx := fes.backendServer.GetBlockchain().GetCommittedTip() + fes.backendServer.GetBlockchain().ChainLock.RUnlock() + if idx == -1 { + _AddBadRequestError(ww, "GetCommittedTipBlockInfo: Problem getting block tip") + return + } + // Return the block tip. + if err := json.NewEncoder(ww).Encode(&lib.CheckpointBlockInfo{ + Height: blockTip.Header.Height, + Hash: blockTip.Hash, + HashHex: blockTip.Hash.String(), + }); err != nil { + _AddBadRequestError(ww, "GetCommittedTipBlockInfo: Problem encoding response as JSON: "+err.Error()) + return + } +} From de2e7011b55d31d9dbef197de15f9ed959a25e4f Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Tue, 9 Apr 2024 18:08:54 -0400 Subject: [PATCH 70/84] Trigger CI From df0500bb12059486fd31b037e271c11ea90f6960 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Tue, 9 Apr 2024 18:34:19 -0400 Subject: [PATCH 71/84] Empty commit for CI From 9a77c3f486b0eb1383b53b1ddeecb2bd179a4b9d Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Wed, 10 Apr 2024 10:57:52 -0700 Subject: [PATCH 72/84] Add an endpoint for easily submitting incomplete atomic transactions. --- routes/server.go | 10 +++ routes/transaction.go | 148 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 2 deletions(-) diff --git a/routes/server.go b/routes/server.go index 5bd0c7ac..3717ca1d 100644 --- a/routes/server.go +++ b/routes/server.go @@ -50,6 +50,7 @@ const ( // transaction.go RoutePathGetTxn = "/api/v0/get-txn" RoutePathSubmitTransaction = "/api/v0/submit-transaction" + RoutePathSubmitAtomicTransaction = "/api/v0/submit-atomic-transaction" RoutePathUpdateProfile = "/api/v0/update-profile" RoutePathSubsidizedUpdateProfile = "/api/v0/subsidized-update-profile" RoutePathExchangeBitcoin = "/api/v0/exchange-bitcoin" @@ -680,6 +681,15 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { PublicAccess, }, + // Route for submitting incomplete atomic transactions and their signatures for network broadcast + { + "SubmitAtomicTransaction", + []string{"POST", "OPTIONS"}, + RoutePathSubmitAtomicTransaction, + fes.SubmitAtomicTransaction, + PublicAccess, + }, + // Temporary route to wipe seedinfo cookies { "DeleteIdentities", diff --git a/routes/transaction.go b/routes/transaction.go index 1a6d1ca5..07006509 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -72,6 +72,136 @@ func (fes *APIServer) GetTxn(ww http.ResponseWriter, req *http.Request) { } } +// SubmitAtomicTransactionRequest is meant to aid in the submission of atomic transactions +// with identity service signed transactions. Specifically, it takes an incomplete atomic transaction +// and "completes" the transaction by adding in identity service signed transactions. +type SubmitAtomicTransactionRequest struct { + // IncompleteAtomicTransaction is a transaction of type TxnTypeAtomicTxnsWrapper who + // is "incomplete" only by missing the signature fields of various inner transactions. + IncompleteAtomicTransaction *lib.MsgDeSoTxn `safeForLogging:"true"` + + // SignedInnerTransactionsHex are the hex-encoded signed inner transactions that + // will be used to complete the atomic transaction. + SignedInnerTransactionsHex []string `safeForLogging:"true"` +} + +type SubmitAtomicTransactionResponse struct { + Transaction *lib.MsgDeSoTxn + TxnHashHex string + TransactionIDBase58Check string +} + +func (fes *APIServer) SubmitAtomicTransaction(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) + requestData := SubmitAtomicTransactionRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("SubmitAtomicTransaction: Problem parsing request body: %v", err)) + return + } + + // Fetch the incomplete atomic transaction. + atomicTxn := requestData.IncompleteAtomicTransaction + if atomicTxn == nil { + _AddBadRequestError(ww, fmt.Sprintf("SubmitAtomicTransaction: IncompleteAtomicTransaction must be set")) + return + } + if atomicTxn.TxnMeta.GetTxnType() != lib.TxnTypeAtomicTxnsWrapper { + _AddBadRequestError(ww, fmt.Sprintf("SubmitAtomicTransaction: "+ + "IncompleteAtomicTransaction must be an atomic transaction")) + return + } + + // Create a map from the pre-signature inner transaction hash to DeSo signature. + innerTxnPreSignatureHashToSignature := make(map[lib.BlockHash]lib.DeSoSignature) + for ii, signedInnerTxnHex := range requestData.SignedInnerTransactionsHex { + // Decode the signed inner transaction. + signedTxnBytes, err := hex.DecodeString(signedInnerTxnHex) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "SubmitAtomicTransaction: Problem decoding signed transaction hex: %v", err)) + return + } + + // Deserialize the signed transaction. + signedInnerTxn := &lib.MsgDeSoTxn{} + if err := signedInnerTxn.FromBytes(signedTxnBytes); err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "SubmitAtomicTransaction: Problem deserializing signed transaction %d from bytes: %v", + ii, err)) + return + } + + // Verify the signature is present. + if signedInnerTxn.Signature.Sign == nil { + _AddBadRequestError(ww, fmt.Sprintf( + "SubmitAtomicTransaction: Signed transaction %d hex missing signature", ii)) + return + } + + // Find the pre-signature DeSo transaction hash. + // NOTE: We do not use the lib.MsgDeSoTxn.Hash() function here as + // the transactions included in the atomic transaction do not yet + // have their signature fields set. + preSignatureInnerTxnBytes, err := signedInnerTxn.ToBytes(true) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "SubmitAtomicTransaction: Problem serializing "+ + "signed transaction %d without signature: %v", ii, err)) + return + } + preSignatureInnerTxnHash := lib.Sha256DoubleHash(preSignatureInnerTxnBytes) + innerTxnPreSignatureHashToSignature[*preSignatureInnerTxnHash] = signedInnerTxn.Signature + } + + // Based on the provided signatures, complete the atomic transaction. + for jj, innerTxn := range atomicTxn.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns { + // Skip signed inner transactions. + if innerTxn.Signature.Sign != nil { + continue + } + + // Find the pre-signature DeSo transaction hash for this transaction. + preSignatureInnerTxnBytes, err := innerTxn.ToBytes(true) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "SubmitAtomicTransaction: Problem serializing "+ + "transaction %d of atomic transaction wrapper without signature: %v", jj, err)) + return + } + preSignatureInnerTxnHash := lib.Sha256DoubleHash(preSignatureInnerTxnBytes) + + // Check that we have the signature. + if _, exists := innerTxnPreSignatureHashToSignature[*preSignatureInnerTxnHash]; !exists { + _AddBadRequestError(ww, fmt.Sprintf( + "SubmitAtomicTransaction: Transaction %d in atomic transaction still missing signature", jj)) + return + } + + // Set the signature in the atomic transaction. + atomicTxn.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[jj].Signature = + innerTxnPreSignatureHashToSignature[*preSignatureInnerTxnHash] + } + + // Verify and broadcast the completed atomic transaction. + if err := fes.backendServer.VerifyAndBroadcastTransaction(atomicTxn); err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubmitAtomicTransaction: Problem broadcasting transaction: %v", err)) + return + } + + res := &SubmitAtomicTransactionResponse{ + Transaction: atomicTxn, + TxnHashHex: atomicTxn.Hash().String(), + TransactionIDBase58Check: lib.PkToString(atomicTxn.Hash()[:], fes.Params), + } + + if err := json.NewEncoder(ww).Encode(res); err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "SubmitAtomicTransaction: Problem encoding response as JSON: %v", err)) + return + } +} + type SubmitTransactionRequest struct { TransactionHex string `safeForLogging:"true"` } @@ -643,10 +773,14 @@ type SubsidizedUpdateProfileResponse struct { // // The caller on receipt of this response should sign the update profile // transaction and then submit the atomic transaction. + // + // For convenience, the returned UpdateProfileTransactionHex field can be used in the frontend to sign + // the update profile transaction. IncompleteAtomicTransaction *lib.MsgDeSoTxn + UpdateProfileTransactionHex string } -// SubsidizedUpdateProfile +// SubsidizedUpdateProfile ... func (fes *APIServer) SubsidizedUpdateProfile(ww http.ResponseWriter, req *http.Request) { decoder := json.NewDecoder(io.LimitReader(req.Body, MaxRequestBodySizeBytes)) requestData := UpdateProfileRequest{} @@ -822,9 +956,19 @@ func (fes *APIServer) SubsidizedUpdateProfile(ww http.ResponseWriter, req *http. } atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[0].Signature.SetSignature(basicTransferSignature) - // (5) Return the atomic transaction wrapper to the user. + // (5) Collect the update profile bytes so the frontend can easily sign it. + updateProfileTxnBytes, err := + atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[1].ToBytes(true) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem serializing update profile transaction: %v", err)) + return + } + + // (6) Return the atomic transaction wrapper to the user. res := SubsidizedUpdateProfileResponse{ IncompleteAtomicTransaction: atomicTxnWrapper, + UpdateProfileTransactionHex: hex.EncodeToString(updateProfileTxnBytes), } if err = json.NewEncoder(ww).Encode(res); err != nil { _AddBadRequestError(ww, From e67fe2ab573f329ddff9cf74c6460bb8999404b2 Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Thu, 11 Apr 2024 10:00:00 -0700 Subject: [PATCH 73/84] Fix submit-atomic-transaction by using incomplete atomic hex. --- routes/transaction.go | 63 ++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/routes/transaction.go b/routes/transaction.go index 07006509..2d774506 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -76,9 +76,9 @@ func (fes *APIServer) GetTxn(ww http.ResponseWriter, req *http.Request) { // with identity service signed transactions. Specifically, it takes an incomplete atomic transaction // and "completes" the transaction by adding in identity service signed transactions. type SubmitAtomicTransactionRequest struct { - // IncompleteAtomicTransaction is a transaction of type TxnTypeAtomicTxnsWrapper who + // IncompleteAtomicTransactionHex is a hex encoded transaction of type TxnTypeAtomicTxnsWrapper who // is "incomplete" only by missing the signature fields of various inner transactions. - IncompleteAtomicTransaction *lib.MsgDeSoTxn `safeForLogging:"true"` + IncompleteAtomicTransactionHex string `safeForLogging:"true"` // SignedInnerTransactionsHex are the hex-encoded signed inner transactions that // will be used to complete the atomic transaction. @@ -100,9 +100,19 @@ func (fes *APIServer) SubmitAtomicTransaction(ww http.ResponseWriter, req *http. } // Fetch the incomplete atomic transaction. - atomicTxn := requestData.IncompleteAtomicTransaction - if atomicTxn == nil { - _AddBadRequestError(ww, fmt.Sprintf("SubmitAtomicTransaction: IncompleteAtomicTransaction must be set")) + atomicTxnBytes, err := hex.DecodeString(requestData.IncompleteAtomicTransactionHex) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubmitAtomicTransaction: "+ + "Problem deserializing atomic transaction hex: %v", err)) + return + } + atomicTxn := &lib.MsgDeSoTxn{} + err = atomicTxn.FromBytes(atomicTxnBytes) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubmitAtomicTransaction: "+ + "Problem deserializing atomic transaction from bytes: %v", err)) return } if atomicTxn.TxnMeta.GetTxnType() != lib.TxnTypeAtomicTxnsWrapper { @@ -775,9 +785,11 @@ type SubsidizedUpdateProfileResponse struct { // transaction and then submit the atomic transaction. // // For convenience, the returned UpdateProfileTransactionHex field can be used in the frontend to sign - // the update profile transaction. - IncompleteAtomicTransaction *lib.MsgDeSoTxn - UpdateProfileTransactionHex string + // the update profile transaction. The IncompleteAtomicTransactionHex field is used in the frontend + // to prevent any typescript precision errors due to the sensitive nature of atomic transactions. + IncompleteAtomicTransaction *lib.MsgDeSoTxn + IncompleteAtomicTransactionHex string + UpdateProfileTransactionHex string } // SubsidizedUpdateProfile ... @@ -928,14 +940,24 @@ func (fes *APIServer) SubsidizedUpdateProfile(ww http.ResponseWriter, req *http. return } - // (3a) Validate the atomic transaction wrapper has sufficient fees paid. - txnBytes, err := atomicTxnWrapper.ToBytes(true) + // (4) Sign the basic transfer transaction within the atomic transaction wrapper. + basicTransferSignature, err := + atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[0].Sign(subsidizationPrivateKey) + if err != nil { + _AddBadRequestError(ww, + fmt.Sprintf("SubsidizedUpdateProfile: Problem signing basic transfer transaction: %v", err)) + return + } + atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[0].Signature.SetSignature(basicTransferSignature) + + // (5) Validate the atomic transaction wrapper has sufficient fees paid. + atomicTxnBytes, err := atomicTxnWrapper.ToBytes(true) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SubsidizedUpdateProfile: Problem serializing transaction: %v", err)) return } - txnSizeBytes := uint64(len(txnBytes)) + txnSizeBytes := uint64(len(atomicTxnBytes)) if txnSizeBytes != 0 && utxoView.GlobalParamsEntry.MinimumNetworkFeeNanosPerKB != 0 { // Check for overflow or minimum network fee not met. if totalFees != ((totalFees*1000)/1000) || @@ -946,17 +968,7 @@ func (fes *APIServer) SubsidizedUpdateProfile(ww http.ResponseWriter, req *http. } } - // (4) Sign the basic transfer transaction within the atomic transaction wrapper. - basicTransferSignature, err := - atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[0].Sign(subsidizationPrivateKey) - if err != nil { - _AddBadRequestError(ww, - fmt.Sprintf("SubsidizedUpdateProfile: Problem signing basic transfer transaction: %v", err)) - return - } - atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[0].Signature.SetSignature(basicTransferSignature) - - // (5) Collect the update profile bytes so the frontend can easily sign it. + // (6) Collect the update profile bytes so the frontend can easily sign it. updateProfileTxnBytes, err := atomicTxnWrapper.TxnMeta.(*lib.AtomicTxnsWrapperMetadata).Txns[1].ToBytes(true) if err != nil { @@ -965,10 +977,11 @@ func (fes *APIServer) SubsidizedUpdateProfile(ww http.ResponseWriter, req *http. return } - // (6) Return the atomic transaction wrapper to the user. + // (7) Return the atomic transaction wrapper to the user. res := SubsidizedUpdateProfileResponse{ - IncompleteAtomicTransaction: atomicTxnWrapper, - UpdateProfileTransactionHex: hex.EncodeToString(updateProfileTxnBytes), + IncompleteAtomicTransaction: atomicTxnWrapper, + IncompleteAtomicTransactionHex: hex.EncodeToString(atomicTxnBytes), + UpdateProfileTransactionHex: hex.EncodeToString(updateProfileTxnBytes), } if err = json.NewEncoder(ww).Encode(res); err != nil { _AddBadRequestError(ww, From f6eccb51527d346499762d90255d66743137a466 Mon Sep 17 00:00:00 2001 From: Jon Pollock Date: Thu, 11 Apr 2024 10:06:17 -0700 Subject: [PATCH 74/84] Use mempool is update profile subsidization. --- routes/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/transaction.go b/routes/transaction.go index ed1c9161..dd478aa5 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -937,7 +937,7 @@ func (fes *APIServer) SubsidizedUpdateProfile(ww http.ResponseWriter, req *http. // (3) Wrap the two transactions in an atomic transaction wrapper. atomicTxnWrapper, totalFees, err := fes.blockchain.CreateAtomicTxnsWrapper( - []*lib.MsgDeSoTxn{basicTransferTxn, updateProfileTxn}, nil) + []*lib.MsgDeSoTxn{basicTransferTxn, updateProfileTxn}, nil, fes.backendServer.GetMempool()) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("SubsidizedUpdateProfile: Problem constructing atomic transaction wrapper: %v", err)) From 4bcee2d40b71a2abf103d9bc559c66304e214090 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:52:57 -0400 Subject: [PATCH 75/84] Update node info endpoint to return info about connections to validators (#586) --- routes/admin_node.go | 65 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/routes/admin_node.go b/routes/admin_node.go index 21692b7c..fec25442 100644 --- a/routes/admin_node.go +++ b/routes/admin_node.go @@ -63,6 +63,26 @@ type PeerResponse struct { IsSyncPeer bool } +type RemoteNodeResponse struct { + // The latest block height the validator is at. + LatestBlockHeight uint64 + + // RemoteNodeStatus is the string representation of the RemoteNode's status. + RemoteNodeStatus string + + // PeerResponse is the IP and port of the peer the validator is connected to. + PeerResponse *PeerResponse + + // PeerConnected is a boolean indicating whether the peer is connected. + PeerConnected bool + + // ValidatorResponse is the ValidatorEntry converted to a human-readable response. + ValidatorResponse *ValidatorResponse + + // IsValidator is a boolean indicating whether the remote node is a validator. + IsValidator bool +} + // NodeControlResponse ... type NodeControlResponse struct { // The current status the DeSo node is at in terms of syncing the DeSo @@ -73,6 +93,8 @@ type NodeControlResponse struct { DeSoInboundPeers []*PeerResponse DeSoUnconnectedPeers []*PeerResponse + RemoteNodeConnections []*RemoteNodeResponse + MinerPublicKeys []string } @@ -197,6 +219,23 @@ func (fes *APIServer) _handleNodeControlGetInfo( publicKey.SerializeCompressed(), fes.Params)) } + // Get the network manager connections + networkManagerConnections := fes.backendServer.GetNetworkManagerConnections() + uncommittedTipView, err := fes.backendServer.GetBlockchain().GetUncommittedTipView() + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("NodeControl: Problem getting uncommitted tip view: %v", err)) + return + } + remoteNodeConnections := make([]*RemoteNodeResponse, 0) + for _, connection := range networkManagerConnections { + remoteNodeConnection, err := _remoteNodeToResponse(connection, uncommittedTipView, fes.Params) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf("NodeControl: Problem getting remote node response: %v", err)) + return + } + remoteNodeConnections = append(remoteNodeConnections, remoteNodeConnection) + } + res := NodeControlResponse{ DeSoStatus: desoNodeStatus, @@ -205,6 +244,8 @@ func (fes *APIServer) _handleNodeControlGetInfo( DeSoUnconnectedPeers: desoUnconnectedPeers, MinerPublicKeys: minerPublicKeyStrs, + + RemoteNodeConnections: remoteNodeConnections, } if err := json.NewEncoder(ww).Encode(res); err != nil { _AddBadRequestError(ww, fmt.Sprintf("NodeControl: Problem encoding response as JSON: %v", err)) @@ -212,6 +253,30 @@ func (fes *APIServer) _handleNodeControlGetInfo( } } +func _remoteNodeToResponse(remoteNode *lib.RemoteNode, utxoView *lib.UtxoView, params *lib.DeSoParams) (*RemoteNodeResponse, error) { + remoteNodeResponse := &RemoteNodeResponse{} + remoteNodeResponse.PeerResponse = &PeerResponse{ + IP: remoteNode.GetPeer().IP(), + ProtocolPort: remoteNode.GetPeer().Port(), + } + remoteNodeResponse.RemoteNodeStatus = remoteNode.GetStatus().String() + remoteNodeResponse.PeerConnected = remoteNode.GetPeer().Connected() + remoteNodeResponse.IsValidator = remoteNode.IsValidator() + remoteNodeResponse.LatestBlockHeight = remoteNode.GetLatestBlockHeight() + if remoteNodeResponse.IsValidator { + blsPublicKeyPKIDPairEntry, err := utxoView.GetBLSPublicKeyPKIDPairEntry(remoteNode.GetValidatorPublicKey()) + if err != nil { + return nil, fmt.Errorf("_remoteNodeToResponse: Problem getting BLS public key PKID pair entry: %v", err) + } + validatorEntry, err := utxoView.GetValidatorByPKID(blsPublicKeyPKIDPairEntry.PKID) + if err != nil { + return nil, fmt.Errorf("_remoteNodeToResponse: Problem getting validator entry: %v", err) + } + remoteNodeResponse.ValidatorResponse = _convertValidatorEntryToResponse(utxoView, validatorEntry, params) + } + return nil, nil +} + func (fes *APIServer) _handleConnectDeSoNode( ww http.ResponseWriter, ip string, protocolPort uint16) { From 53adfeed13af6121f11d8758914c0d7899654a90 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:29:22 -0400 Subject: [PATCH 76/84] Upgrade go to 1.22 (#585) --- .github/workflows/ci.yaml | 4 ++-- Dockerfile | 2 +- go.mod | 2 +- test.Dockerfile | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 811c1372..08435898 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,7 +15,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: "1.20" + go-version: "1.22" - name: Checkout branch uses: actions/checkout@v3 @@ -32,7 +32,7 @@ jobs: # - name: Install go # uses: actions/setup-go@v3 # with: -# go-version: "1.20" +# go-version: "1.22" # # - name: Install os dependencies # run: sudo apt-get install -y libvips-tools libvips-dev && vips -v diff --git a/Dockerfile b/Dockerfile index 26b104bd..e9d21f64 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ RUN apk update RUN apk upgrade RUN apk add --update bash cmake g++ gcc git make vips-dev -COPY --from=golang:1.20-alpine /usr/local/go/ /usr/local/go/ +COPY --from=golang:1.22-alpine /usr/local/go/ /usr/local/go/ ENV PATH="/usr/local/go/bin:${PATH}" WORKDIR /deso/src diff --git a/go.mod b/go.mod index a5a3ac73..318adc58 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/deso-protocol/backend -go 1.20 +go 1.22 replace github.com/deso-protocol/core => ../core/ diff --git a/test.Dockerfile b/test.Dockerfile index 89bc12bb..53954666 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -4,7 +4,7 @@ RUN apk update RUN apk upgrade RUN apk add --update bash cmake g++ gcc git make vips-dev -COPY --from=golang:1.20-alpine /usr/local/go/ /usr/local/go/ +COPY --from=golang:1.22-alpine /usr/local/go/ /usr/local/go/ ENV PATH="/usr/local/go/bin:${PATH}" # Declare an ARG for the branch name with a default value of "main" From 9f108080ed8b13d8b0f7907539fc942e96fb32f3 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:31:30 -0400 Subject: [PATCH 77/84] Upgrade deps (#569) --- config/config.go | 2 +- go.mod | 225 +++-- go.sum | 901 ++++++++---------- routes/access_group_test.go | 6 +- routes/admin_fees.go | 2 +- routes/admin_node.go | 12 +- routes/admin_referrals.go | 4 +- routes/admin_transaction.go | 4 +- routes/admin_user.go | 2 +- routes/associations_test.go | 4 +- routes/dao_coin_exchange.go | 40 +- routes/dao_coin_exchange_test.go | 34 +- routes/eth.go | 2 +- routes/exchange.go | 6 +- routes/lockups.go | 12 +- routes/media.go | 4 +- routes/message.go | 7 +- routes/post.go | 2 +- routes/referrals.go | 2 +- routes/server.go | 6 +- routes/transaction.go | 17 +- routes/tutorial.go | 2 +- routes/user.go | 2 +- routes/wyre.go | 2 +- scripts/pos/validator_registration.go | 2 +- scripts/tools/bitclout_pub_key_to_btc_addr.go | 4 +- scripts/tools/bitclout_pub_key_to_eth_addr.go | 2 +- scripts/tools/daodao-message-notify.go | 4 +- scripts/tools/toolslib/basic_transfer.go | 2 +- scripts/tools/toolslib/creator_coins.go | 2 +- scripts/tools/toolslib/dao.go | 2 +- scripts/tools/toolslib/diamonds.go | 2 +- scripts/tools/toolslib/jwt.go | 2 +- scripts/tools/toolslib/keys.go | 2 +- scripts/tools/toolslib/messages.go | 2 +- scripts/tools/toolslib/nft.go | 2 +- .../tools/toolslib/offline_basic_transfer.go | 4 +- scripts/tools/toolslib/update_bitcoin.go | 2 +- scripts/tools/toolslib/update_profile.go | 2 +- 39 files changed, 633 insertions(+), 703 deletions(-) diff --git a/config/config.go b/config/config.go index a5e566ec..a180ba70 100644 --- a/config/config.go +++ b/config/config.go @@ -234,7 +234,7 @@ func LoadConfig(coreConfig *coreCmd.Config) *Config { panic(fmt.Sprintf("metamask-airdrop-eth-minimum value %v overflows uint256", metamaskAirdropMinStr)) } } else { - config.MetamaskAirdropEthMinimum = uint256.NewInt() + config.MetamaskAirdropEthMinimum = uint256.NewInt(0) } config.MetamaskAirdropDESONanosAmount = viper.GetUint64("metamask-airdrop-deso-nanos-amount") diff --git a/go.mod b/go.mod index 318adc58..c3ffc721 100644 --- a/go.mod +++ b/go.mod @@ -5,131 +5,176 @@ go 1.22 replace github.com/deso-protocol/core => ../core/ require ( - cloud.google.com/go/storage v1.27.0 - github.com/btcsuite/btcd v0.21.0-beta - github.com/btcsuite/btcutil v1.0.2 - github.com/davecgh/go-spew v1.1.1 - github.com/deso-protocol/core v0.0.0-00010101000000-000000000000 + cloud.google.com/go/storage v1.40.0 + github.com/btcsuite/btcd v0.24.0 + github.com/btcsuite/btcd/btcec/v2 v2.3.3 + github.com/btcsuite/btcd/btcutil v1.1.5 + github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 + github.com/deso-protocol/core v1.2.9 github.com/deso-protocol/go-deadlock v1.0.0 github.com/dgraph-io/badger/v4 v4.2.0 github.com/fatih/structs v1.1.0 - github.com/golang-jwt/jwt/v4 v4.1.0 - github.com/golang/glog v1.0.0 - github.com/gorilla/mux v1.8.0 - github.com/h2non/bimg v1.1.5 - github.com/holiman/uint256 v1.1.1 - github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang/glog v1.2.1 + github.com/gorilla/mux v1.8.1 + github.com/h2non/bimg v1.1.9 + github.com/holiman/uint256 v1.2.4 + github.com/kevinburke/twilio-go v0.0.0-20231009225535-38b36b35294d github.com/mitchellh/go-homedir v1.1.0 - github.com/mitchellh/mapstructure v1.1.2 - github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe - github.com/nyaruka/phonenumbers v1.0.69 + github.com/mitchellh/mapstructure v1.5.0 + github.com/montanaflynn/stats v0.7.1 + github.com/nyaruka/phonenumbers v1.3.4 github.com/pkg/errors v0.9.1 - github.com/sendgrid/sendgrid-go v3.10.0+incompatible - github.com/spf13/cobra v1.1.3 + github.com/sendgrid/sendgrid-go v3.14.0+incompatible + github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.7.1 - github.com/stretchr/testify v1.8.1 + github.com/spf13/viper v1.18.2 + github.com/stretchr/testify v1.9.0 github.com/tyler-smith/go-bip39 v1.1.0 - golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d + golang.org/x/crypto v0.22.0 golang.org/x/image v0.15.0 - golang.org/x/sync v0.1.0 - google.golang.org/api v0.103.0 - gopkg.in/DataDog/dd-trace-go.v1 v1.29.0 + golang.org/x/sync v0.7.0 + google.golang.org/api v0.172.0 + gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 ) require ( - cloud.google.com/go v0.107.0 // indirect - cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go v0.112.2 // indirect + cloud.google.com/go/compute v1.25.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.8.0 // indirect - github.com/DataDog/datadog-go v4.5.0+incompatible // indirect - github.com/Microsoft/go-winio v0.4.16 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect + cloud.google.com/go/iam v1.1.7 // indirect + github.com/AlecAivazis/survey/v2 v2.3.7 // indirect + github.com/DataDog/appsec-internal-go v1.5.0 // indirect + github.com/DataDog/datadog-agent/pkg/obfuscate v0.52.1 // indirect + github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.52.1 // indirect + github.com/DataDog/datadog-go v4.8.3+incompatible // indirect + github.com/DataDog/datadog-go/v5 v5.5.0 // indirect + github.com/DataDog/go-libddwaf/v2 v2.4.2 // indirect + github.com/DataDog/go-sqllexer v0.0.11 // indirect + github.com/DataDog/go-tuf v1.1.0-0.5.2 // indirect + github.com/DataDog/gostackparse v0.7.0 // indirect + github.com/DataDog/sketches-go v1.4.4 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/andygrunwald/go-jira v1.16.0 // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect - github.com/bwesterb/go-ristretto v1.2.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cloudflare/circl v1.1.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/decred/dcrd/lru v1.1.1 // indirect + github.com/bwesterb/go-ristretto v1.2.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudflare/circl v1.3.7 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect + github.com/decred/dcrd/lru v1.1.2 // indirect github.com/deso-protocol/go-merkle-tree v1.0.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/ebitengine/purego v0.7.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/ethereum/go-ethereum v1.9.25 // indirect - github.com/fatih/color v1.13.0 // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/ethereum/go-ethereum v1.13.14 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gernest/mention v2.0.0+incompatible // indirect - github.com/git-chglog/git-chglog v0.0.0-20200414013904-db796966b373 // indirect - github.com/go-pg/pg/v10 v10.10.0 // indirect + github.com/git-chglog/git-chglog v0.15.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-pg/pg/v10 v10.12.0 // indirect github.com/go-pg/zerochecker v0.2.0 // indirect - github.com/gofrs/uuid v4.0.0+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.3 // indirect - github.com/google/flatbuffers v2.0.0+incompatible // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect - github.com/googleapis/gax-go/v2 v2.7.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/imdario/mergo v0.3.8 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/flatbuffers v24.3.25+incompatible // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/huandu/xstrings v1.4.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7 // indirect - github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c // indirect - github.com/klauspost/compress v1.12.3 // indirect - github.com/magiconair/properties v1.8.1 // indirect - github.com/mattn/go-colorable v0.1.9 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/mattn/goveralls v0.0.6 // indirect - github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/kevinburke/rest v0.0.0-20231107185522-a9c371f90234 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/kyokomi/emoji/v2 v2.2.12 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/goveralls v0.0.12 // indirect + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oleiade/lane v1.0.1 // indirect - github.com/onflow/crypto v0.25.0 // indirect - github.com/pelletier/go-toml v1.7.0 // indirect - github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect - github.com/philhofer/fwd v1.1.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/onflow/crypto v0.25.1 // indirect + github.com/outcaste-io/ristretto v0.2.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.0 // indirect + github.com/petermattis/goid v0.0.0-20240327183114-c42a807a84ba // indirect + github.com/philhofer/fwd v1.1.2 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 // indirect github.com/robinjoseph08/go-pg-migrations/v3 v3.0.0 // indirect - github.com/russross/blackfriday/v2 v2.0.1 // indirect - github.com/sendgrid/rest v2.6.4+incompatible // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect + github.com/sendgrid/rest v2.6.9+incompatible // indirect github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/spf13/afero v1.1.2 // indirect - github.com/spf13/cast v1.3.0 // indirect - github.com/spf13/jwalterweatherman v1.0.0 // indirect - github.com/subosito/gotenv v1.2.0 // indirect - github.com/tinylib/msgp v1.1.2 // indirect + github.com/shopspring/decimal v1.3.1 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/tinylib/msgp v1.1.9 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect + github.com/trivago/tgo v1.0.7 // indirect github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df // indirect github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect github.com/ttacon/libphonenumber v1.2.1 // indirect - github.com/unrolled/secure v1.0.8 // indirect - github.com/urfave/cli v1.22.1 // indirect + github.com/unrolled/secure v1.14.0 // indirect + github.com/urfave/cli/v2 v2.27.1 // indirect github.com/vmihailenco/bufpool v0.1.11 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.1 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser v0.1.2 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/net v0.7.0 // indirect - golang.org/x/oauth2 v0.4.0 // indirect - golang.org/x/sys v0.5.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect + go.opentelemetry.io/otel v1.25.0 // indirect + go.opentelemetry.io/otel/metric v1.25.0 // indirect + go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/oauth2 v0.19.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect - golang.org/x/tools v0.6.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - gonum.org/v1/gonum v0.6.1 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect - gopkg.in/AlecAivazis/survey.v1 v1.8.7 // indirect - gopkg.in/ini.v1 v1.51.0 // indirect - gopkg.in/kyokomi/emoji.v1 v1.5.1 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.20.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + gonum.org/v1/gonum v0.15.0 // indirect + google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.2 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - mellium.im/sasl v0.2.1 // indirect + mellium.im/sasl v0.3.1 // indirect ) diff --git a/go.sum b/go.sum index 056a9eb6..41a3cbac 100644 --- a/go.sum +++ b/go.sum @@ -1,125 +1,116 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go v0.112.2 h1:ZaGT6LiG7dBzi6zNOvVZwacaXlmf3lRqnC4DQzqyRQw= +cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= -github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= +cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= +cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= +cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v4.4.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/datadog-go v4.5.0+incompatible h1:MyyuIz5LVAI3Im+0F/tfo64ETyH4sNVynZ29yOiHm50= -github.com/DataDog/datadog-go v4.5.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= +github.com/DataDog/appsec-internal-go v1.5.0 h1:8kS5zSx5T49uZ8dZTdT19QVAvC/B8ByyZdhQKYQWHno= +github.com/DataDog/appsec-internal-go v1.5.0/go.mod h1:pEp8gjfNLtEOmz+iZqC8bXhu0h4k7NUsW/qiQb34k1U= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.52.1 h1:/oxF4p/4XUGNpNw2TE7vDu/pJV3elEAZ+jES0/MWtiI= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.52.1/go.mod h1:AVPQWekk3h9AOC7+plBlNB68Sy6UIGFoMMVUDeSoNoI= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.52.1 h1:mmkGuCHBFuDBpuwNMcqtY1x1I2fCaPH2Br4xPAAjbkM= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.52.1/go.mod h1:JhAilx32dkIgoDkFXquCTfaWDsAOfe+vfBaxbiZoPI0= +github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q= +github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/datadog-go/v5 v5.5.0 h1:G5KHeB8pWBNXT4Jtw0zAkhdxEAWSpWH00geHI6LDrKU= +github.com/DataDog/datadog-go/v5 v5.5.0/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= +github.com/DataDog/go-libddwaf/v2 v2.4.2 h1:ilquGKUmN9/Ty0sIxiEyznVRxP3hKfmH15Y1SMq5gjA= +github.com/DataDog/go-libddwaf/v2 v2.4.2/go.mod h1:gsCdoijYQfj8ce/T2bEDNPZFIYnmHluAgVDpuQOWMZE= +github.com/DataDog/go-sqllexer v0.0.11 h1:OfPBjmayreblOXreszbrOTICNZ3qWrA6Bg4sypvxpbw= +github.com/DataDog/go-sqllexer v0.0.11/go.mod h1:KwkYhpFEVIq+BfobkTC1vfqm4gTi65skV/DpDBXtexc= +github.com/DataDog/go-tuf v1.1.0-0.5.2 h1:4CagiIekonLSfL8GMHRHcHudo1fQnxELS9g4tiAupQ4= +github.com/DataDog/go-tuf v1.1.0-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0= +github.com/DataDog/gostackparse v0.7.0 h1:i7dLkXHvYzHV308hnkvVGDL3BR4FWl7IsXNPz/IGQh4= +github.com/DataDog/gostackparse v0.7.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM= +github.com/DataDog/sketches-go v1.4.4 h1:dF52vzXRFSPOj2IjXSWLvXq3jubL4CI69kwYjJ1w5Z8= +github.com/DataDog/sketches-go v1.4.4/go.mod h1:XR0ns2RtEEF09mDKXiKZiQg+nfZStrq1ZuL1eezeZe0= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/andygrunwald/go-jira v1.16.0 h1:PU7C7Fkk5L96JvPc6vDVIrd99vdPnYudHu4ju2c2ikQ= +github.com/andygrunwald/go-jira v1.16.0/go.mod h1:UQH4IBVxIYWbgagc0LF/k9FRs9xjIiQ8hIcC6HfLwFU= github.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8= -github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/brianvoe/gofakeit v3.18.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= -github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= -github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= -github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= +github.com/btcsuite/btcd v0.24.0 h1:gL3uHE/IaFj6fcZSu03SvqPMSx7s/dPzfpG/atRwWdo= +github.com/btcsuite/btcd v0.24.0/go.mod h1:K4IDc1593s8jKXIF7yS7yCTSxrknB9z0STzc2j6XgE4= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= +github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= +github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= -github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/goleveldb v1.0.0 h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/snappy-go v1.0.0 h1:ZxaA6lo2EpxGddsA8JwWOcxlzRybb444sgmeJQMJGQE= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/bwesterb/go-ristretto v1.2.0 h1:xxWOVbN5m8NNKiSDZXE1jtZvZnC6JSJ9cYFADiZcWtw= -github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= +github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= -github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= -github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/decred/dcrd/lru v1.1.1 h1:kWFDaW0OWx6AD6Ki342c+JPmHbiVdE6rK81pT3fuo/Y= -github.com/decred/dcrd/lru v1.1.1/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/decred/dcrd/lru v1.1.2 h1:KdCzlkxppuoIDGEvCGah1fZRicrDH36IipvlB1ROkFY= +github.com/decred/dcrd/lru v1.1.2/go.mod h1:gEdCVgXs1/YoBvFWt7Scgknbhwik3FgVSzlnCcXL2N8= github.com/deso-protocol/go-deadlock v1.0.0 h1:mw0pHy/19zgC+JFBStuQt1+1Ehv5OKA5NxXqecnL5ic= github.com/deso-protocol/go-deadlock v1.0.0/go.mod h1:K0Wd2OV2x7ck7SMYDraWerpKjFKUeBqaFcwz21tmkb8= github.com/deso-protocol/go-merkle-tree v1.0.0 h1:9zkI5dQsITYy77s4kbTGPQmZnhQ+LsH/kRdL5l/Yzvg= @@ -128,74 +119,67 @@ github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8Bzu github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= -github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= +github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/go-ethereum v1.9.25 h1:mMiw/zOOtCLdGLWfcekua0qPrJTe7FVIiHJ4IKNTfR0= -github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= -github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/ethereum/go-ethereum v1.13.14 h1:EwiY3FZP94derMCIam1iW4HFVrSgIcpsu0HwTQtm6CQ= +github.com/ethereum/go-ethereum v1.13.14/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fergusstrange/embedded-postgres v1.19.0 h1:NqDufJHeA03U7biULlPHZ0pZ10/mDOMKPILEpT50Fyk= -github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fergusstrange/embedded-postgres v1.26.0 h1:mTgUBNST+6zro0TkIb9Fuo9Qg8mSU0ILus9jZKmFmJg= +github.com/fergusstrange/embedded-postgres v1.26.0/go.mod h1:t/MLs0h9ukYM6FSt99R7InCHs1nW0ordoVCcnzmpTYw= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gernest/mention v2.0.0+incompatible h1:pTXnujBC6tqlw5awDkLojq92TXbt0F+4+8FBlQC+di8= github.com/gernest/mention v2.0.0+incompatible/go.mod h1:/z3Hb+4gaPF+vL8og/lj6Au5j8hh5EfU7/EknmDUuO4= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/git-chglog/git-chglog v0.0.0-20200414013904-db796966b373 h1:MHrlpWOOFhCfY1L9iCIUy5cv5HgDtempICenzJt+7ws= github.com/git-chglog/git-chglog v0.0.0-20200414013904-db796966b373/go.mod h1:Dcsy1kii/xFyNad5JqY/d0GO5mu91sungp5xotbm3Yk= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/git-chglog/git-chglog v0.15.4 h1:BwPDj7AghQTfpXO+UxG4mZM5MUTe9wfDuenF3jpyNf0= +github.com/git-chglog/git-chglog v0.15.4/go.mod h1:BmWdTpqBVzPjKNrBTZGcQCrQV9zq6gFKurhWNnJbYDA= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-pg/pg/v10 v10.5.0/go.mod h1:BfgPoQnD2wXNd986RYEHzikqv9iE875PrFaZ9vXvtNM= -github.com/go-pg/pg/v10 v10.10.0 h1:xc5zWYQ/55XI8pk5NkK+ixXqbJh1vnOun3VODPmbYfY= -github.com/go-pg/pg/v10 v10.10.0/go.mod h1:EmoJGYErc+stNN/1Jf+o4csXuprjxcRztBnn6cHe38E= +github.com/go-pg/pg/v10 v10.12.0 h1:rBmfDDHTN7FQW0OemYmcn5UuBy6wkYWgh/Oqt1OBEB8= +github.com/go-pg/pg/v10 v10.12.0/go.mod h1:USA08CdIasAn0F6wC1nBf5nQhMHewVQodWoH89RPXaI= github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU= github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo= -github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0= -github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -209,16 +193,13 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI= -github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= +github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -227,261 +208,204 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20210125172800-10e9aeb4a998/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 h1:zIaiqGYDQwa4HVx5wGRTXbx38Pqxjemn4BP98wpzpXo= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/h2non/bimg v1.1.5 h1:o3xsUBxM8s7+e7PmpiWIkEYdeYayJ94eh4cJLx67m1k= -github.com/h2non/bimg v1.1.5/go.mod h1:R3+UiYwkK4rQl6KVFTOFJHitgLbZXBZNFh2cv3AEbp8= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/h2non/bimg v1.1.9 h1:WH20Nxko9l/HFm4kZCA3Phbgu2cbHvYzxwxn9YROEGg= +github.com/h2non/bimg v1.1.9/go.mod h1:R3+UiYwkK4rQl6KVFTOFJHitgLbZXBZNFh2cv3AEbp8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= -github.com/holiman/uint256 v1.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw= -github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/log15 v3.0.0-testing.5+incompatible/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7 h1:K8qael4LemsmJCGt+ccI8b0fCNFDttmEu3qtpFt3G0M= github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7/go.mod h1:/Pk5i/SqYdYv1cie5wGwoZ4P6TpgMi+Yf58mtJSHdOw= -github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c h1:hnbwWED5rIu+UaMkLR3JtnscMVGqp35lfzQwLuZAAUY= -github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c/go.mod h1:pD+iEcdAGVXld5foVN4e24zb/6fnb60tgZPZ3P/3T/I= -github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73 h1:PSsFm2SRpq9LnaRHLz4u9ZZ3liWjgXM6OMxXE4/qlgY= -github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73/go.mod h1:Fm9alkN1/LPVY1eqD/psyMwPWE4VWl4P01/nTYZKzBk= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kevinburke/rest v0.0.0-20231107185522-a9c371f90234 h1:wMgTpL99gp1GUW9n7rtSB7Oad7xAKX+KgHftVctE7RQ= +github.com/kevinburke/rest v0.0.0-20231107185522-a9c371f90234/go.mod h1:dcLMT8KO9krIMJQ4578Lex1Su6ewuJUqEDeQ1nTORug= +github.com/kevinburke/twilio-go v0.0.0-20231009225535-38b36b35294d h1:EtrDnkat2jYA91OGm+dizL8RaF+GGy3EY/zLW59JhV8= +github.com/kevinburke/twilio-go v0.0.0-20231009225535-38b36b35294d/go.mod h1:4ljZgMTVLbuhqWMcxXPQRsGJ/XJ0xdGzbdLOJACnYco= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU= -github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kyokomi/emoji/v2 v2.2.12 h1:sSVA5nH9ebR3Zji1o31wu3yOwD1zKXQA2z0zUyeit60= +github.com/kyokomi/emoji/v2 v2.2.12/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/goveralls v0.0.6 h1:cr8Y0VMo/MnEZBjxNN/vh6G90SZ7IMb6lms1dzMoO+Y= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/goveralls v0.0.6/go.mod h1:h8b4ow6FxSPMQHF6o2ve3qsclnffZjYTNEKmLesRwqw= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mattn/goveralls v0.0.12 h1:PEEeF0k1SsTjOBQ8FOmrOAoCu4ytuMaWCnWe94zxbCg= +github.com/mattn/goveralls v0.0.12/go.mod h1:44ImGEUfmqH8bBtaMrYKsM65LXfNLWmwaxFGjZwgMSQ= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nyaruka/phonenumbers v1.0.69 h1:j9h62+vaRMdcdjQfCdI2iHAtd1jjKYVQuJRQEu6mFIY= -github.com/nyaruka/phonenumbers v1.0.69/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= +github.com/nyaruka/phonenumbers v1.3.4 h1:bF1Wdh++fxw09s3surhVeBhXEcUKG07pHeP8HQXqjn8= +github.com/nyaruka/phonenumbers v1.3.4/go.mod h1:Ut+eFwikULbmCenH6InMKL9csUNLyxHuBLyfkpum11s= github.com/oleiade/lane v1.0.1 h1:hXofkn7GEOubzTwNpeL9MaNy8WxolCYb9cInAIeqShU= github.com/oleiade/lane v1.0.1/go.mod h1:IyTkraa4maLfjq/GmHR+Dxb4kCMtEGeb+qmhlrQ5Mk4= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onflow/crypto v0.25.0 h1:BeWbLsh3ZD13Ej+Uky6kg1PL1ZIVBDVX+2MVBNwqddg= -github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= +github.com/onflow/crypto v0.25.1 h1:0txy2PKPMM873JbpxQNbJmuOJtD56bfs48RQfm0ts5A= +github.com/onflow/crypto v0.25.1/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= +github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= +github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= +github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/petermattis/goid v0.0.0-20240327183114-c42a807a84ba h1:3jPgmsFGBID1wFfU2AbYocNcN4wqU68UaHSdMjiw/7U= +github.com/petermattis/goid v0.0.0-20240327183114-c42a807a84ba/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 h1:Qp27Idfgi6ACvFQat5+VJvlYToylpM/hcyLBI3WaKPA= +github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= github.com/robinjoseph08/go-pg-migrations/v3 v3.0.0 h1:0/H63lDsoNYVn5YmP6VLDEnnKkoVYiHx7udTWCK4BUI= github.com/robinjoseph08/go-pg-migrations/v3 v3.0.0/go.mod h1:nOkSFfwwDUBFnDDQqMRC2p4PDE7GZb/KSVqILVB3bmw= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sendgrid/rest v2.6.4+incompatible h1:lq6gAQxLwVBf3mVyCCSHI6mgF+NfaJFJHjT0kl6SSo8= -github.com/sendgrid/rest v2.6.4+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE= -github.com/sendgrid/sendgrid-go v3.10.0+incompatible h1:aSYyurHxEZSDy7kxhvZ4fH0inNkEEmRssZNbAmETR2c= -github.com/sendgrid/sendgrid-go v3.10.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA= +github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU= +github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0= +github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE= +github.com/sendgrid/sendgrid-go v3.14.0+incompatible h1:KDSasSTktAqMJCYClHVE94Fcif2i7P7wzISv1sU6DUA= +github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y= -github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= -github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -491,275 +415,243 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= -github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= -github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= +github.com/tinylib/msgp v1.1.9 h1:SHf3yoO2sGA0veCJeCBYLHuttAVFHGm2RHgNodW7wQU= +github.com/tinylib/msgp v1.1.9/go.mod h1:BCXGB54lDD8qUEPmiG0cQQUANC4IUQyB2ItS2UDlO/k= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= +github.com/trivago/tgo v1.0.7 h1:uaWH/XIy9aWYWpjm2CU3RpcqZXmX2ysQ9/Go+d9gyrM= +github.com/trivago/tgo v1.0.7/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc= github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df h1:Y2l28Jr3vOEeYtxfVbMtVfOdAwuUqWaP9fvNKiBVeXY= github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df/go.mod h1:pnyouUty/nBr/zm3GYwTIt+qFTLWbdjeLjZmJdzJOu8= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4= github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/unrolled/secure v1.0.8 h1:JaMvKbe4CRt8oyxVXn+xY+6jlqd7pyJNSVkmsBxxQsM= -github.com/unrolled/secure v1.0.8/go.mod h1:fO+mEan+FLB0CdEnHf6Q4ZZVNqG+5fuLFnP8p0BXDPI= -github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= +github.com/unrolled/secure v1.14.0 h1:u9vJTU/pR4Bny0ntLUMxdfLtmIRGvQf2sEFuA0TG9AE= +github.com/unrolled/secure v1.14.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= +github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94= github.com/vmihailenco/bufpool v0.1.11/go.mod h1:AFf/MOy3l2CFTKbxwt0mp2MwnqjNEs5H/UxrkA5jxTQ= github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1/go.mod h1:xlngVLeyQ/Qi05oQxhQ+oTuqa03RjMwMfk/7/TCs+QI= github.com/vmihailenco/msgpack/v5 v5.0.0-beta.8/go.mod h1:HVxBVPUK/+fZMonk4bi1islLa8V3cfnBug0+4dykPzo= -github.com/vmihailenco/msgpack/v5 v5.3.1 h1:0i85a4dsZh8mC//wmyyTEzidDLPQfQAxZIOLtafGbFY= -github.com/vmihailenco/msgpack/v5 v5.3.1/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 h1:zvpPXY7RfYAGSdYQLjp6zxdJNSYD/+FFoCTQN9IPxBs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0/go.mod h1:BMn8NB1vsxTljvuorms2hyOs8IBuuBEq0pl7ltOfy30= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= +go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= +go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= +go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= +go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= +golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201026173827-119d4633e4d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.6.1 h1:/LSrTrgZtpbXyAR6+0e152SROCkJJSh7goYWVmdPFGc= -gonum.org/v1/gonum v0.6.1/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= +gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= +google.golang.org/api v0.172.0 h1:/1OcMZGPmW1rX2LCu2CmGUD1KXK1+pfzxotxyRUCCdk= +google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw= +google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw= +google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda h1:b6F6WIV4xHHD0FA4oIyzU6mHWg2WI2X1RBehwa5QN38= +google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda/go.mod h1:AHcE/gZH76Bk/ROZhQphlRoWo5xKDEtz3eVEO1LfA8c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -770,35 +662,27 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/AlecAivazis/survey.v1 v1.8.7 h1:oBJqtgsyBLg9K5FK9twNUbcPnbCPoh+R9a+7nag3qJM= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/AlecAivazis/survey.v1 v1.8.7/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= -gopkg.in/DataDog/dd-trace-go.v1 v1.29.0 h1:3C1EEjgFTPqrnS2SXuSqkBbZGacIOPJ7ScGJk4nrP9s= -gopkg.in/DataDog/dd-trace-go.v1 v1.29.0/go.mod h1:FLwUDeuH0z5hkvgvd04/M3MHQN4AF5pQDnedeWRWvok= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 h1:jeZxE4ZlfAc+R0zO5TEmJBwOLet3NThsOfYJeSQg1x0= +gopkg.in/DataDog/dd-trace-go.v1 v1.62.0/go.mod h1:YTvYkk3PTsfw0OWrRFxV/IQ5Gy4nZ5TRvxTAP3JcIzs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/kyokomi/emoji.v1 v1.5.1 h1:beetH5mWDMzFznJ+Qzd5KVHp79YKhVUMcdO8LpRLeGw= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/kyokomi/emoji.v1 v1.5.1/go.mod h1:N9AZ6hi1jHOPn34PsbpufQZUcKftSD7WgS2pgpmH4Lg= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -806,13 +690,12 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/gotraceui v0.2.0 h1:dmNsfQ9Vl3GwbiVD7Z8d/osC6WtGGrasyrC2suc4ZIQ= +honnef.co/go/gotraceui v0.2.0/go.mod h1:qHo4/W75cA3bX0QQoSvDjbJa4R8mAyyFjbWAj63XElc= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w= mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ= +mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= +mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= diff --git a/routes/access_group_test.go b/routes/access_group_test.go index ef058388..4354513c 100644 --- a/routes/access_group_test.go +++ b/routes/access_group_test.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" "github.com/stretchr/testify/assert" @@ -19,7 +19,7 @@ import ( func signTransaction(t *testing.T, txn *lib.MsgDeSoTxn) { privKeyBytes, _, err := lib.Base58CheckDecode(senderPrivString) require.NoError(t, err) - privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) + privKey, _ := btcec.PrivKeyFromBytes(privKeyBytes) txnSignature, err := txn.Sign(privKey) require.NoError(t, err) txn.Signature.SetSignature(txnSignature) @@ -141,7 +141,7 @@ func TestAPIAccessGroupBaseGroupMembership(t *testing.T) { func generateRandomPublicKey(t *testing.T) (publicKeyBytes []byte) { t.Helper() require := require.New(t) - randomPrivateKey, err := btcec.NewPrivateKey(btcec.S256()) + randomPrivateKey, err := btcec.NewPrivateKey() require.NoError(err) randomPublicKeyBytes := randomPrivateKey.PubKey().SerializeCompressed() return randomPublicKeyBytes diff --git a/routes/admin_fees.go b/routes/admin_fees.go index d8c64829..22186d1b 100644 --- a/routes/admin_fees.go +++ b/routes/admin_fees.go @@ -5,7 +5,7 @@ import ( "encoding/gob" "encoding/json" "fmt" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" "github.com/golang/glog" "io" diff --git a/routes/admin_node.go b/routes/admin_node.go index fec25442..c133567b 100644 --- a/routes/admin_node.go +++ b/routes/admin_node.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" ) @@ -192,8 +192,8 @@ func (fes *APIServer) _handleNodeControlGetInfo( desoAddrs := fes.backendServer.AddrMgr.AddressCache() sort.Slice(desoAddrs, func(ii, jj int) bool { // Use a hash to get a random but deterministic ordering. - hashI := string(lib.Sha256DoubleHash([]byte(desoAddrs[ii].IP.String() + fmt.Sprintf(":%d", desoAddrs[ii].Port)))[:]) - hashJ := string(lib.Sha256DoubleHash([]byte(desoAddrs[jj].IP.String() + fmt.Sprintf(":%d", desoAddrs[jj].Port)))[:]) + hashI := string(lib.Sha256DoubleHash([]byte(desoAddrs[ii].Addr.String() + fmt.Sprintf(":%d", desoAddrs[ii].Port)))[:]) + hashJ := string(lib.Sha256DoubleHash([]byte(desoAddrs[jj].Addr.String() + fmt.Sprintf(":%d", desoAddrs[jj].Port)))[:]) return hashI < hashJ }) @@ -201,12 +201,12 @@ func (fes *APIServer) _handleNodeControlGetInfo( if len(desoUnconnectedPeers) >= 250 { break } - addr := netAddr.IP.String() + fmt.Sprintf(":%d", netAddr.Port) + addr := netAddr.Addr.String() + fmt.Sprintf(":%d", netAddr.Port) if _, exists := existingDeSoPeers[addr]; exists { continue } desoUnconnectedPeers = append(desoUnconnectedPeers, &PeerResponse{ - IP: netAddr.IP.String(), + IP: netAddr.Addr.String(), ProtocolPort: netAddr.Port, // Unconnected peers are not sync peers so leave it set to false. }) @@ -450,7 +450,7 @@ func (fes *APIServer) NodeControl(ww http.ResponseWriter, req *http.Request) { _AddBadRequestError(ww, fmt.Sprintf("NodeControlRequest: Problem decoding miner public key from base58 %s: %v", pkStr, err)) return } - pk, err := btcec.ParsePubKey(publicKeyBytes, btcec.S256()) + pk, err := btcec.ParsePubKey(publicKeyBytes) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("NodeControlRequest: Problem parsing miner public key %s: %v", pkStr, err)) return diff --git a/routes/admin_referrals.go b/routes/admin_referrals.go index aa62fb8d..543a283c 100644 --- a/routes/admin_referrals.go +++ b/routes/admin_referrals.go @@ -16,8 +16,8 @@ import ( "github.com/davecgh/go-spew/spew" - "github.com/btcsuite/btcd/btcec" - "github.com/btcsuite/btcutil/base58" + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil/base58" "github.com/deso-protocol/core/lib" "github.com/golang/glog" "github.com/pkg/errors" diff --git a/routes/admin_transaction.go b/routes/admin_transaction.go index dc7c634f..b7a547b0 100644 --- a/routes/admin_transaction.go +++ b/routes/admin_transaction.go @@ -8,7 +8,7 @@ import ( "net/http" "strings" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" ) @@ -596,7 +596,7 @@ func (fes *APIServer) TestSignTransactionWithDerivedKey(ww http.ResponseWriter, _AddBadRequestError(ww, fmt.Sprintf("TestSignTransactionWithDerivedKey: Problem decoding seed hex %v", err)) return } - privKeyBytes, _ := btcec.PrivKeyFromBytes(btcec.S256(), privBytes) + privKeyBytes, _ := btcec.PrivKeyFromBytes(privBytes) // Sign the transaction with a derived key. Since the txn extraData must be modified, // we also get new transaction bytes, along with the signature. diff --git a/routes/admin_user.go b/routes/admin_user.go index bc9eb092..1566b2a2 100644 --- a/routes/admin_user.go +++ b/routes/admin_user.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" ) diff --git a/routes/associations_test.go b/routes/associations_test.go index f47d568b..1f84d2b6 100644 --- a/routes/associations_test.go +++ b/routes/associations_test.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "encoding/json" "errors" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/config" coreCmd "github.com/deso-protocol/core/cmd" "github.com/deso-protocol/core/lib" @@ -644,7 +644,7 @@ func newTestApiServer(t *testing.T) *APIServer { func signTxn(t *testing.T, txn *lib.MsgDeSoTxn, privKeyBase58Check string) { privKeyBytes, _, err := lib.Base58CheckDecode(privKeyBase58Check) require.NoError(t, err) - privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) + privKey, _ := btcec.PrivKeyFromBytes(privKeyBytes) txnSignature, err := txn.Sign(privKey) require.NoError(t, err) txn.Signature.SetSignature(txnSignature) diff --git a/routes/dao_coin_exchange.go b/routes/dao_coin_exchange.go index 090fee66..90ebce44 100644 --- a/routes/dao_coin_exchange.go +++ b/routes/dao_coin_exchange.go @@ -374,7 +374,7 @@ func (fes *APIServer) GetBestAvailableExchangeRateCoinsToBuyPerCoinToSell( return "0", nil } - bestExchangeRate := uint256.NewInt() + bestExchangeRate := uint256.NewInt(0) for _, order := range orders { // ScaledExchangeRateCoinsToSellPerCoinToBuy has the buying coin is the denominator, so we want to find // the highest available ScaledExchangeRateCoinsToSellPerCoinToBuy @@ -463,8 +463,8 @@ func CalculateScaledExchangeRateFromPriceString( // Scale up the price to account for DAO Coin -> DESO trades if buyingCoinPublicKeyBase58Check == DESOCoinIdentifierString { - product := uint256.NewInt() - overflow := product.MulOverflow(rawScaledPrice, getDESOToDAOCoinBaseUnitsScalingFactor()) + product := uint256.NewInt(0) + _, overflow := product.MulOverflow(rawScaledPrice, getDESOToDAOCoinBaseUnitsScalingFactor()) if overflow { return nil, errors.Errorf("Overflow when converting %v to a scaled exchange rate", price) } @@ -475,7 +475,7 @@ func CalculateScaledExchangeRateFromPriceString( if sellingCoinPublicKeyBase58Check == DESOCoinIdentifierString { // We intentionally want to round the exchange rate down for BID orders so precision loss does not prevent the // order from not getting matched with an ASK order with the same input price - quotient := uint256.NewInt().Div(rawScaledPrice, getDESOToDAOCoinBaseUnitsScalingFactor()) + quotient := uint256.NewInt(0).Div(rawScaledPrice, getDESOToDAOCoinBaseUnitsScalingFactor()) if quotient.IsZero() { return nil, errors.Errorf("The %v produces a scaled exchange rate that is too small", price) } @@ -514,15 +514,15 @@ func CalculateScaledExchangeRateFromFloat( } if buyingCoinPublicKeyBase58Check == DESOCoinIdentifierString { // Buying coin is $DESO - product := uint256.NewInt() - overflow := product.MulOverflow(rawScaledExchangeRate, getDESOToDAOCoinBaseUnitsScalingFactor()) + product := uint256.NewInt(0) + _, overflow := product.MulOverflow(rawScaledExchangeRate, getDESOToDAOCoinBaseUnitsScalingFactor()) if overflow { return nil, errors.Errorf("Overflow when convering %f to a scaled exchange rate", exchangeRateCoinsToSellPerCoinToBuy) } return product, nil } else if sellingCoinPublicKeyBase58Check == DESOCoinIdentifierString { // Selling coin is $DESO - quotient := uint256.NewInt().Div(rawScaledExchangeRate, getDESOToDAOCoinBaseUnitsScalingFactor()) + quotient := uint256.NewInt(0).Div(rawScaledExchangeRate, getDESOToDAOCoinBaseUnitsScalingFactor()) if quotient.IsZero() { return nil, errors.Errorf("The float value %f is too small to produce a scaled exchange rate", exchangeRateCoinsToSellPerCoinToBuy) } @@ -687,7 +687,7 @@ func calculateQuantityToFillAsDAOCoinBaseUnits(quantityToFill string) (*uint256. func calculateQuantityToFillAsDESONanos(quantityToFill string) (*uint256.Int, error) { scaledQuantity, err := lib.ScaleFloatFormatStringToUint256( quantityToFill, - uint256.NewInt().SetUint64(lib.NanosPerUnit), + uint256.NewInt(lib.NanosPerUnit), ) if err != nil { return nil, err @@ -766,9 +766,9 @@ func orderFillTypeToUint64( // returns (1e18 / 1e9), which represents the difference in scaling factor for DAO coin base units and $DESO nanos func getDESOToDAOCoinBaseUnitsScalingFactor() *uint256.Int { - return uint256.NewInt().Div( + return uint256.NewInt(0).Div( lib.BaseUnitsPerCoin, - uint256.NewInt().SetUint64(lib.NanosPerUnit), + uint256.NewInt(lib.NanosPerUnit), ) } @@ -869,14 +869,14 @@ func (fes *APIServer) validateTransactorSellingCoinBalance( sellingCoinPKID := &lib.ZeroPKID // Calculate current balance for transactor. - transactorSellingBalanceBaseUnits := uint256.NewInt() + transactorSellingBalanceBaseUnits := uint256.NewInt(0) if sellingDAOCoinCreatorPublicKeyBase58Check == DESOCoinIdentifierString { // Get $DESO balance nanos. desoBalanceNanos, err := utxoView.GetDeSoBalanceNanosForPublicKey(transactorPublicKey) if err != nil { return errors.Errorf("Error getting transactor DESO balance: %v", err) } - transactorSellingBalanceBaseUnits = uint256.NewInt().SetUint64(desoBalanceNanos) + transactorSellingBalanceBaseUnits = uint256.NewInt(desoBalanceNanos) } else { // Get selling coin PKID and public key from public key base58 check. sellingCoinPKID, err = fes.getPKIDFromPublicKeyBase58Check( @@ -904,7 +904,7 @@ func (fes *APIServer) validateTransactorSellingCoinBalance( } // Calculate total selling quantity for current order. - totalSellingBaseUnits := uint256.NewInt() + totalSellingBaseUnits := uint256.NewInt(0) if operationType == DAOCoinLimitOrderOperationTypeStringASK { totalSellingBaseUnits = quantityToFillInBaseUnits } else if operationType == DAOCoinLimitOrderOperationTypeStringBID { @@ -1023,7 +1023,7 @@ func (fes *APIServer) getDAOCoinLimitOrderSimulatedExecutionResult( if buyingDAOCoinCreatorPublicKeyBase58Check == DESOCoinIdentifierString { // If the buying coin is DESO, then the ending balance change will have the transaction fee subtracted. In order to // isolate the amount of the buying coin bought as a part of this order, we need to add back the transaction fee - buyingCoinEndingBalance.Add(buyingCoinEndingBalance, uint256.NewInt().SetUint64(txnFees)) + buyingCoinEndingBalance.Add(buyingCoinEndingBalance, uint256.NewInt(txnFees)) } sellingCoinEndingBalance, err := fes.getTransactorDesoOrDaoCoinBalance(utxoView, transactorPublicKeyBase58Check, sellingDAOCoinCreatorPublicKeyBase58Check) @@ -1034,7 +1034,7 @@ func (fes *APIServer) getDAOCoinLimitOrderSimulatedExecutionResult( // If the selling coin is DESO, then the ending balance will have the network fee subtracted. In order to isolate // the amount of the selling coin sold as a part of this order, we need to add back the transaction fee to the // ending balance - sellingCoinEndingBalance.Add(sellingCoinEndingBalance, uint256.NewInt().SetUint64(txnFees)) + sellingCoinEndingBalance.Add(sellingCoinEndingBalance, uint256.NewInt(txnFees)) } buyingCoinBalanceChange := "0.0" @@ -1050,13 +1050,13 @@ func (fes *APIServer) getDAOCoinLimitOrderSimulatedExecutionResult( // Convert buying coin balance change from uint256 to as a decimal string (ex: 1.23) buyingCoinBalanceChange = lib.FormatScaledUint256AsDecimalString( - uint256.NewInt().Sub(buyingCoinEndingBalance, buyingCoinStartingBalance).ToBig(), + uint256.NewInt(0).Sub(buyingCoinEndingBalance, buyingCoinStartingBalance).ToBig(), getScalingFactorForCoin(buyingDAOCoinCreatorPublicKeyBase58Check).ToBig(), ) // Convert selling coin balance change from uint256 to as a decimal string (ex: 1.23) sellingCoinBalanceChange = lib.FormatScaledUint256AsDecimalString( - uint256.NewInt().Sub(sellingCoinStartingBalance, sellingCoinEndingBalance).ToBig(), + uint256.NewInt(0).Sub(sellingCoinStartingBalance, sellingCoinEndingBalance).ToBig(), getScalingFactorForCoin(sellingDAOCoinCreatorPublicKeyBase58Check).ToBig(), ) @@ -1082,7 +1082,7 @@ func (fes *APIServer) getTransactorDesoOrDaoCoinBalance( if err != nil { return nil, errors.Errorf("Error getting transactor DESO balance: %v", err) } - return uint256.NewInt().SetUint64(desoBalanceNanos), nil + return uint256.NewInt(desoBalanceNanos), nil } daoCoinCreatorPublicKey, _, err := lib.Base58CheckDecode(desoOrDAOCoinCreatorPublicKeyBase58Check) @@ -1100,7 +1100,7 @@ func (fes *APIServer) getTransactorDesoOrDaoCoinBalance( func getScalingFactorForCoin(coinCreatorPublicKeyBase58Check string) *uint256.Int { if coinCreatorPublicKeyBase58Check == DESOCoinIdentifierString { - return uint256.NewInt().SetUint64(lib.NanosPerUnit) + return uint256.NewInt(lib.NanosPerUnit) } - return uint256.NewInt().Set(lib.BaseUnitsPerCoin) + return uint256.NewInt(0).Set(lib.BaseUnitsPerCoin) } diff --git a/routes/dao_coin_exchange_test.go b/routes/dao_coin_exchange_test.go index 5b3d03c3..57e1ffdb 100644 --- a/routes/dao_coin_exchange_test.go +++ b/routes/dao_coin_exchange_test.go @@ -41,17 +41,17 @@ func TestCalculateScaledExchangeRate(t *testing.T) { // Test when buying coin is a DAO coin and selling coin is a DAO coin, for various exchange rates for _, testCase := range successTestCases { exchangeRate := testCase.floatValue - expectedScaledExchangeRate := uint256.NewInt() + expectedScaledExchangeRate := uint256.NewInt(0) if testCase.expectedWholeNumberDigits > 0 { - expectedScaledExchangeRate = uint256.NewInt().Mul( - lib.OneE38, uint256.NewInt().SetUint64(uint64(testCase.expectedWholeNumberDigits)), + expectedScaledExchangeRate = uint256.NewInt(0).Mul( + lib.OneE38, uint256.NewInt(uint64(testCase.expectedWholeNumberDigits)), ) } if testCase.decimalDigitExponent < 0 { expectedScaledExchangeRate.Add( expectedScaledExchangeRate, - uint256.NewInt().Div(lib.OneE38, uint256.NewInt().SetUint64(uint64(-testCase.decimalDigitExponent))), + uint256.NewInt(0).Div(lib.OneE38, uint256.NewInt(uint64(-testCase.decimalDigitExponent))), ) } scaledExchangeRate, err := CalculateScaledExchangeRateFromFloat( @@ -72,7 +72,7 @@ func TestCalculateScaledExchangeRate(t *testing.T) { ) require.NoError(t, err) // expectedScaledExchangeRate / 1e9 - expectedScaledExchangeRate := uint256.NewInt().Div(lib.OneE38, desoToDaoCoinBaseUnitsScalingFactor) + expectedScaledExchangeRate := uint256.NewInt(0).Div(lib.OneE38, desoToDaoCoinBaseUnitsScalingFactor) require.Equal(t, expectedScaledExchangeRate, scaledExchangeRate) } @@ -84,7 +84,7 @@ func TestCalculateScaledExchangeRate(t *testing.T) { 1.0, ) require.NoError(t, err) - expectedScaledExchangeRate := uint256.NewInt().Mul( + expectedScaledExchangeRate := uint256.NewInt(0).Mul( lib.OneE38, desoToDaoCoinBaseUnitsScalingFactor, ) @@ -211,9 +211,9 @@ func TestCalculateExchangeRateAsFloat(t *testing.T) { desoToDaoCoinBaseUnitsScalingFactor := getDESOToDAOCoinBaseUnitsScalingFactor() // equivalent to 100.00000001 - scaledExchangeRate := uint256.NewInt().Add( - uint256.NewInt().Mul(lib.OneE38, uint256.NewInt().SetUint64(100)), // 100 - uint256.NewInt().Div(lib.OneE38, uint256.NewInt().SetUint64(100000000)), // 0.00000001 + scaledExchangeRate := uint256.NewInt(0).Add( + uint256.NewInt(0).Mul(lib.OneE38, uint256.NewInt(100)), // 100 + uint256.NewInt(0).Div(lib.OneE38, uint256.NewInt(100000000)), // 0.00000001 ) expectedExchangeRate := 100.00000001 @@ -257,7 +257,7 @@ func TestCalculatePriceStringFromScaledExchangeRate(t *testing.T) { desoToDaoCoinBaseUnitsScalingFactor := getDESOToDAOCoinBaseUnitsScalingFactor() // equivalent to 100 scaled up by 1e38 - scaledExchangeRate := uint256.NewInt().Mul(lib.OneE38, uint256.NewInt().SetUint64(100)) + scaledExchangeRate := uint256.NewInt(0).Mul(lib.OneE38, uint256.NewInt(100)) expectedStringExchangeRate := "100.0" expectedInvertedStringExchangeRate := "0.01" @@ -292,7 +292,7 @@ func TestCalculatePriceStringFromScaledExchangeRate(t *testing.T) { daoCoinPubKeyBase58Check, desoPubKeyBase58Check, // need to account for exchange rate being scaled up by 1e9 for orders selling deso for dao coins - uint256.NewInt().Div(scaledExchangeRate, desoToDaoCoinBaseUnitsScalingFactor), + uint256.NewInt(0).Div(scaledExchangeRate, desoToDaoCoinBaseUnitsScalingFactor), DAOCoinLimitOrderOperationTypeStringBID, ) require.NoError(t, err) @@ -305,7 +305,7 @@ func TestCalculatePriceStringFromScaledExchangeRate(t *testing.T) { daoCoinPubKeyBase58Check, desoPubKeyBase58Check, // need to account for exchange rate being scaled up by 1e9 for orders selling deso for dao coins - uint256.NewInt().Div(scaledExchangeRate, desoToDaoCoinBaseUnitsScalingFactor), + uint256.NewInt(0).Div(scaledExchangeRate, desoToDaoCoinBaseUnitsScalingFactor), DAOCoinLimitOrderOperationTypeStringASK, ) require.NoError(t, err) @@ -318,7 +318,7 @@ func TestCalculatePriceStringFromScaledExchangeRate(t *testing.T) { desoPubKeyBase58Check, daoCoinPubKeyBase58Check, // need to account for exchange rate being scaled down by 1e9 for orders selling dao coins for deso - uint256.NewInt().Mul(scaledExchangeRate, desoToDaoCoinBaseUnitsScalingFactor), + uint256.NewInt(0).Mul(scaledExchangeRate, desoToDaoCoinBaseUnitsScalingFactor), DAOCoinLimitOrderOperationTypeStringBID, ) require.NoError(t, err) @@ -331,7 +331,7 @@ func TestCalculatePriceStringFromScaledExchangeRate(t *testing.T) { desoPubKeyBase58Check, daoCoinPubKeyBase58Check, // need to account for exchange rate being scaled down by 1e9 for orders selling dao coins for deso - uint256.NewInt().Mul(scaledExchangeRate, desoToDaoCoinBaseUnitsScalingFactor), + uint256.NewInt(0).Mul(scaledExchangeRate, desoToDaoCoinBaseUnitsScalingFactor), DAOCoinLimitOrderOperationTypeStringASK, ) require.NoError(t, err) @@ -340,7 +340,7 @@ func TestCalculatePriceStringFromScaledExchangeRate(t *testing.T) { } func TestCalculateQuantityToFillAsBaseUnits(t *testing.T) { - expectedValueIfDESO := uint256.NewInt().SetUint64(lib.NanosPerUnit) + expectedValueIfDESO := uint256.NewInt(lib.NanosPerUnit) expectedValueIfDAOCoin := &(*lib.BaseUnitsPerCoin) quantity := float64(1) @@ -535,7 +535,7 @@ func TestCalculateStringQuantityFromBaseUnits(t *testing.T) { desoPubKeyBase58Check, daoCoinPubKeyBase58Check, DAOCoinLimitOrderOperationTypeStringBID, - uint256.NewInt().SetUint64(0), + uint256.NewInt(0), ) require.Error(t, err) } @@ -546,7 +546,7 @@ func TestCalculateStringQuantityFromBaseUnits(t *testing.T) { desoPubKeyBase58Check, daoCoinPubKeyBase58Check, DAOCoinLimitOrderOperationTypeStringASK, - uint256.NewInt().SetUint64(0), + uint256.NewInt(0), ) require.Error(t, err) } diff --git a/routes/eth.go b/routes/eth.go index 2a8f9d5f..f88187d3 100644 --- a/routes/eth.go +++ b/routes/eth.go @@ -14,8 +14,8 @@ import ( "strings" "time" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcutil" "golang.org/x/crypto/sha3" "encoding/hex" diff --git a/routes/exchange.go b/routes/exchange.go index 5f035dbb..7733c067 100644 --- a/routes/exchange.go +++ b/routes/exchange.go @@ -15,7 +15,7 @@ import ( "github.com/pkg/errors" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/golang/glog" bip39 "github.com/tyler-smith/go-bip39" ) @@ -724,7 +724,7 @@ func (fes *APIServer) APITransferDeSo(ww http.ResponseWriter, rr *http.Request) "base58 private key: %v", err)) return } - senderPriv, senderPub := btcec.PrivKeyFromBytes(btcec.S256(), senderPrivBytes) + senderPriv, senderPub := btcec.PrivKeyFromBytes(senderPrivBytes) if senderPriv == nil { APIAddError(ww, fmt.Sprintf("APITransferDeSo: Problem parsing sender "+ "base58 private key")) @@ -739,7 +739,7 @@ func (fes *APIServer) APITransferDeSo(ww http.ResponseWriter, rr *http.Request) "base58 public key %s: %v", transferDeSoRequest.RecipientPublicKeyBase58Check, err)) return } - recipientPub, err := btcec.ParsePubKey(recipientPubBytes, btcec.S256()) + recipientPub, err := btcec.ParsePubKey(recipientPubBytes) if err != nil { APIAddError(ww, fmt.Sprintf("APITransferDeSo: Problem encoding recipient "+ "base58 public key %s: %v", transferDeSoRequest.RecipientPublicKeyBase58Check, err)) diff --git a/routes/lockups.go b/routes/lockups.go index 45d7f08f..2810907c 100644 --- a/routes/lockups.go +++ b/routes/lockups.go @@ -660,19 +660,19 @@ func (fes *APIServer) LockedBalanceEntries(ww http.ResponseWriter, req *http.Req // NOTE: It's possible to create multiple locked balance entries that are impossible to unlock due to overflow. // As such, if the addition triggers an overflow we will just ignore adding more and use the max Uint256. var newTotalLockedBaseUnits *uint256.Int - if uint256.NewInt().Sub( + if uint256.NewInt(0).Sub( lib.MaxUint256, &cumulativeResponse.TotalLockedBaseUnits).Lt(&lockedBalanceEntry.BalanceBaseUnits) { newTotalLockedBaseUnits = lib.MaxUint256 } else { - newTotalLockedBaseUnits = uint256.NewInt().Add( + newTotalLockedBaseUnits = uint256.NewInt(0).Add( &cumulativeResponse.TotalLockedBaseUnits, &lockedBalanceEntry.BalanceBaseUnits) } // Compute how much (if any) is unlockable in the give entry. - unlockableBaseUnitsFromEntry := uint256.NewInt() - newTotalUnlockableBaseUnits := uint256.NewInt() + unlockableBaseUnitsFromEntry := uint256.NewInt(0) + newTotalUnlockableBaseUnits := uint256.NewInt(0) if lockedBalanceEntry.UnlockTimestampNanoSecs < currentTimestampNanoSecs { // Check if the locked balance entry is unvested or vested. if lockedBalanceEntry.UnlockTimestampNanoSecs == lockedBalanceEntry.VestingEndTimestampNanoSecs { @@ -687,12 +687,12 @@ func (fes *APIServer) LockedBalanceEntries(ww http.ResponseWriter, req *http.Req } } } - if uint256.NewInt().Sub( + if uint256.NewInt(0).Sub( lib.MaxUint256, &cumulativeResponse.UnlockableBaseUnits).Lt(unlockableBaseUnitsFromEntry) { newTotalUnlockableBaseUnits = lib.MaxUint256 } else { - newTotalUnlockableBaseUnits = uint256.NewInt().Add( + newTotalUnlockableBaseUnits = uint256.NewInt(0).Add( &cumulativeResponse.UnlockableBaseUnits, unlockableBaseUnitsFromEntry) } diff --git a/routes/media.go b/routes/media.go index 95e25746..85c0e51f 100644 --- a/routes/media.go +++ b/routes/media.go @@ -101,9 +101,9 @@ func validateImageSize(encodedImageContentBytes []byte, extension string) error if err != nil { return errors.Wrap(err, "validateImageSize: Problem decoding image config") } - if imageConfig.Width > bimg.MaxSize || imageConfig.Height > bimg.MaxSize { + if imageConfig.Width > bimg.MaxSize() || imageConfig.Height > bimg.MaxSize() { return fmt.Errorf("validateImageSize: image too large. Max dimensions are %v x %v. ImageConfig dimensions are %v x %v", - bimg.MaxSize, bimg.MaxSize, imageConfig.Width, imageConfig.Height) + bimg.MaxSize(), bimg.MaxSize(), imageConfig.Width, imageConfig.Height) } return nil } diff --git a/routes/message.go b/routes/message.go index e30f75a8..61eaf869 100644 --- a/routes/message.go +++ b/routes/message.go @@ -5,7 +5,8 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" + ecdsa2 "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" "io" @@ -1008,13 +1009,13 @@ func VerifyBytesSignature(signerPk, data, signatureBytes []byte) error { bytes := lib.Sha256DoubleHash(data) // Convert signatureBytes to *btcec.Signature. - sign, err := btcec.ParseDERSignature(signatureBytes, btcec.S256()) + sign, err := ecdsa2.ParseDERSignature(signatureBytes) if err != nil { return errors.Wrapf(err, "VerifyBytesSignature: Problem parsing access signatureBytes: ") } // Parse signer public key - ownerPk, err := btcec.ParsePubKey(signerPk, btcec.S256()) + ownerPk, err := btcec.ParsePubKey(signerPk) if err != nil { return errors.Wrapf(err, "VerifyBytesSignature: Problem parsing signer public key: ") } diff --git a/routes/post.go b/routes/post.go index 4011b435..fdcfecdd 100644 --- a/routes/post.go +++ b/routes/post.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" ) diff --git a/routes/referrals.go b/routes/referrals.go index bf89f2b1..c6335e8a 100644 --- a/routes/referrals.go +++ b/routes/referrals.go @@ -6,7 +6,7 @@ import ( "io" "net/http" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" ) diff --git a/routes/server.go b/routes/server.go index bcdcdc69..1a379b5a 100644 --- a/routes/server.go +++ b/routes/server.go @@ -13,7 +13,7 @@ import ( "github.com/pkg/errors" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/config" "github.com/golang-jwt/jwt/v4" "github.com/tyler-smith/go-bip39" @@ -2645,7 +2645,7 @@ func (fes *APIServer) ValidateJWT(publicKey string, jwtToken string) (bool, erro return false, errors.Wrapf(err, "Problem decoding public key") } - pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256()) + pubKey, err := btcec.ParsePubKey(pubKeyBytes) if err != nil { return false, errors.Wrapf(err, "Problem parsing public key") } @@ -2663,7 +2663,7 @@ func (fes *APIServer) ValidateJWT(publicKey string, jwtToken string) (bool, erro if err != nil { return nil, errors.Wrapf(err, "Problem decoding derived public key") } - derivedPublicKey, err := btcec.ParsePubKey(derivedPublicKeyBytes, btcec.S256()) + derivedPublicKey, err := btcec.ParsePubKey(derivedPublicKeyBytes) if err != nil { return nil, errors.Wrapf(err, "Problem parsing derived public key bytes") } diff --git a/routes/transaction.go b/routes/transaction.go index 403a4a15..e530e5a3 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + ecdsa2 "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" "io" "math/big" "net/http" @@ -15,10 +16,10 @@ import ( "github.com/holiman/uint256" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btcutil" "github.com/deso-protocol/core/lib" "github.com/golang/glog" "github.com/pkg/errors" @@ -806,7 +807,7 @@ func (fes *APIServer) ExchangeBitcoinStateless(ww http.ResponseWriter, req *http _AddBadRequestError(ww, fmt.Sprintf("ExchangeBitcoinStateless: Failed to decode hash: %v", err)) return } - parsedSig, err := btcec.ParseDERSignature(sig, btcec.S256()) + parsedSig, err := ecdsa2.ParseDERSignature(sig) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("ExchangeBitcoinStateless: Parsing "+ "signature failed: %v: %v", signedHash, err)) @@ -2471,7 +2472,7 @@ func (fes *APIServer) DAOCoin(ww http.ResponseWriter, req *http.Request) { "DAOCoin: Must be profile owner in order to perform %v operation", requestData.OperationType)) return } - zero := uint256.NewInt() + zero := uint256.NewInt(0) if operationType == lib.DAOCoinOperationTypeMint && requestData.CoinsToMintNanos.Eq(zero) { _AddBadRequestError(ww, fmt.Sprint("DAOCoin: Cannot mint 0 coins")) return @@ -2779,7 +2780,7 @@ func (fes *APIServer) CreateDAOCoinLimitOrder(ww http.ResponseWriter, req *http. } // Validated and parse price to a scaled exchange rate - scaledExchangeRateCoinsToSellPerCoinToBuy := uint256.NewInt() + scaledExchangeRateCoinsToSellPerCoinToBuy := uint256.NewInt(0) if requestData.Price == "" && requestData.ExchangeRateCoinsToSellPerCoinToBuy == 0 { err = errors.Errorf("Price must be provided as a valid decimal string (ex: 1.23)") } else if requestData.Price != "" { @@ -2805,7 +2806,7 @@ func (fes *APIServer) CreateDAOCoinLimitOrder(ww http.ResponseWriter, req *http. } // Parse and validated quantity - quantityToFillInBaseUnits := uint256.NewInt() + quantityToFillInBaseUnits := uint256.NewInt(0) if requestData.Quantity == "" && requestData.QuantityToFill == 0 { err = errors.Errorf("Quantity must be provided as a valid decimal string (ex: 1.23)") } else if requestData.Quantity != "" { @@ -2964,7 +2965,7 @@ func (fes *APIServer) CreateDAOCoinMarketOrder(ww http.ResponseWriter, req *http // Validate and convert quantity to base units // Parse and validated quantity - quantityToFillInBaseUnits := uint256.NewInt() + quantityToFillInBaseUnits := uint256.NewInt(0) if requestData.Quantity == "" && requestData.QuantityToFill == 0 { err = errors.Errorf("CreateDAOCoinMarketOrder: Quantity must be provided as a valid decimal string (ex: 1.23)") } else if requestData.Quantity != "" { @@ -3033,7 +3034,7 @@ func (fes *APIServer) CreateDAOCoinMarketOrder(ww http.ResponseWriter, req *http } // override the initial value and explicitly set to 0 for clarity - zeroUint256 := uint256.NewInt().SetUint64(0) + zeroUint256 := uint256.NewInt(0) res, err := fes.createDAOCoinLimitOrderResponse( utxoView, diff --git a/routes/tutorial.go b/routes/tutorial.go index e335334b..a78b6625 100644 --- a/routes/tutorial.go +++ b/routes/tutorial.go @@ -8,7 +8,7 @@ import ( "net/http" "time" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" ) diff --git a/routes/user.go b/routes/user.go index b837375e..5fa54bc5 100644 --- a/routes/user.go +++ b/routes/user.go @@ -17,7 +17,7 @@ import ( "github.com/holiman/uint256" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/dgraph-io/badger/v4" "github.com/gorilla/mux" diff --git a/routes/wyre.go b/routes/wyre.go index 48482205..3329ee5c 100644 --- a/routes/wyre.go +++ b/routes/wyre.go @@ -8,7 +8,7 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" "github.com/fatih/structs" "github.com/golang/glog" diff --git a/scripts/pos/validator_registration.go b/scripts/pos/validator_registration.go index cbe79499..b1100f82 100644 --- a/scripts/pos/validator_registration.go +++ b/scripts/pos/validator_registration.go @@ -9,7 +9,7 @@ import ( "net/http" "time" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/bls" "github.com/deso-protocol/core/lib" diff --git a/scripts/tools/bitclout_pub_key_to_btc_addr.go b/scripts/tools/bitclout_pub_key_to_btc_addr.go index 0870eb89..3530c360 100644 --- a/scripts/tools/bitclout_pub_key_to_btc_addr.go +++ b/scripts/tools/bitclout_pub_key_to_btc_addr.go @@ -3,8 +3,8 @@ package main import ( "flag" "fmt" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcutil" "github.com/deso-protocol/core/lib" "os" ) @@ -16,7 +16,7 @@ func main() { if err != nil { panic(err) } - //pubKey, err := btcec.ParsePubKey(pkBytes, btcec.S256()) + //pubKey, err := btcec.ParsePubKey(pkBytes) //if err != nil { // panic(err) //} diff --git a/scripts/tools/bitclout_pub_key_to_eth_addr.go b/scripts/tools/bitclout_pub_key_to_eth_addr.go index 25faf544..53968f01 100644 --- a/scripts/tools/bitclout_pub_key_to_eth_addr.go +++ b/scripts/tools/bitclout_pub_key_to_eth_addr.go @@ -4,8 +4,8 @@ import ( "encoding/hex" "flag" "fmt" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcutil" "github.com/deso-protocol/core/lib" "golang.org/x/crypto/sha3" "os" diff --git a/scripts/tools/daodao-message-notify.go b/scripts/tools/daodao-message-notify.go index 5c3cd38a..abe497e3 100644 --- a/scripts/tools/daodao-message-notify.go +++ b/scripts/tools/daodao-message-notify.go @@ -6,7 +6,7 @@ import ( "encoding/json" "flag" "fmt" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/backend/scripts/tools/toolslib" "github.com/deso-protocol/core/lib" @@ -303,7 +303,7 @@ func main() { continue } } - toBTCECPubKey, err := btcec.ParsePubKey(toKeyBytes, btcec.S256()) + toBTCECPubKey, err := btcec.ParsePubKey(toKeyBytes) if err != nil { if err != nil { fmt.Printf("main(): Ran into an error when trying to btcec parse pk (%s): %s\n", toPubKey, err.Error()) diff --git a/scripts/tools/toolslib/basic_transfer.go b/scripts/tools/toolslib/basic_transfer.go index 74d2e515..b0d3376f 100644 --- a/scripts/tools/toolslib/basic_transfer.go +++ b/scripts/tools/toolslib/basic_transfer.go @@ -3,7 +3,7 @@ package toolslib import ( "bytes" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" diff --git a/scripts/tools/toolslib/creator_coins.go b/scripts/tools/toolslib/creator_coins.go index b6e5a9f6..21aff923 100644 --- a/scripts/tools/toolslib/creator_coins.go +++ b/scripts/tools/toolslib/creator_coins.go @@ -3,7 +3,7 @@ package toolslib import ( "bytes" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" diff --git a/scripts/tools/toolslib/dao.go b/scripts/tools/toolslib/dao.go index 878122c7..0f5b3bda 100644 --- a/scripts/tools/toolslib/dao.go +++ b/scripts/tools/toolslib/dao.go @@ -3,7 +3,7 @@ package toolslib import ( "bytes" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/lib" "github.com/holiman/uint256" diff --git a/scripts/tools/toolslib/diamonds.go b/scripts/tools/toolslib/diamonds.go index 58f3da8a..09f6bdd6 100644 --- a/scripts/tools/toolslib/diamonds.go +++ b/scripts/tools/toolslib/diamonds.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/hex" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" diff --git a/scripts/tools/toolslib/jwt.go b/scripts/tools/toolslib/jwt.go index c8ca3ffe..3c5b6365 100644 --- a/scripts/tools/toolslib/jwt.go +++ b/scripts/tools/toolslib/jwt.go @@ -1,7 +1,7 @@ package toolslib import ( - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/fatih/structs" "github.com/golang-jwt/jwt/v4" "github.com/pkg/errors" diff --git a/scripts/tools/toolslib/keys.go b/scripts/tools/toolslib/keys.go index c9e87c57..760aa8fa 100644 --- a/scripts/tools/toolslib/keys.go +++ b/scripts/tools/toolslib/keys.go @@ -1,7 +1,7 @@ package toolslib import ( - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" "github.com/tyler-smith/go-bip39" ) diff --git a/scripts/tools/toolslib/messages.go b/scripts/tools/toolslib/messages.go index 827ed174..95713c36 100644 --- a/scripts/tools/toolslib/messages.go +++ b/scripts/tools/toolslib/messages.go @@ -3,7 +3,7 @@ package toolslib import ( "bytes" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" diff --git a/scripts/tools/toolslib/nft.go b/scripts/tools/toolslib/nft.go index 1588c026..fdb151df 100644 --- a/scripts/tools/toolslib/nft.go +++ b/scripts/tools/toolslib/nft.go @@ -3,7 +3,7 @@ package toolslib import ( "bytes" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" diff --git a/scripts/tools/toolslib/offline_basic_transfer.go b/scripts/tools/toolslib/offline_basic_transfer.go index 2bbe6c36..b87ec315 100644 --- a/scripts/tools/toolslib/offline_basic_transfer.go +++ b/scripts/tools/toolslib/offline_basic_transfer.go @@ -1,14 +1,14 @@ package toolslib import ( - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" ) // ACCOUNT GENERATION func accountGeneration() (*btcec.PrivateKey, *btcec.PublicKey, error) { - privKey, err := btcec.NewPrivateKey(btcec.S256()) + privKey, err := btcec.NewPrivateKey() if err != nil { return nil, nil, errors.Wrap(err, "accountGeneration() failed to generate private key") } diff --git a/scripts/tools/toolslib/update_bitcoin.go b/scripts/tools/toolslib/update_bitcoin.go index bbebf72e..fa04408f 100644 --- a/scripts/tools/toolslib/update_bitcoin.go +++ b/scripts/tools/toolslib/update_bitcoin.go @@ -3,7 +3,7 @@ package toolslib import ( "bytes" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" diff --git a/scripts/tools/toolslib/update_profile.go b/scripts/tools/toolslib/update_profile.go index f581677e..d4687b16 100644 --- a/scripts/tools/toolslib/update_profile.go +++ b/scripts/tools/toolslib/update_profile.go @@ -3,7 +3,7 @@ package toolslib import ( "bytes" "encoding/json" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" "github.com/deso-protocol/backend/routes" "github.com/deso-protocol/core/lib" "github.com/pkg/errors" From 254a9ca6e9bbf42cc169119d146ecee25a88df7f Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Thu, 11 Apr 2024 17:30:43 -0400 Subject: [PATCH 78/84] Empty commit for CI From cec7df9a16f05ca4e9ddfda199e34c4fe3bdb7a9 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 11 Apr 2024 19:51:44 -0400 Subject: [PATCH 79/84] Fix remote node to response (#587) --- routes/admin_node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/admin_node.go b/routes/admin_node.go index c133567b..5d15db06 100644 --- a/routes/admin_node.go +++ b/routes/admin_node.go @@ -274,7 +274,7 @@ func _remoteNodeToResponse(remoteNode *lib.RemoteNode, utxoView *lib.UtxoView, p } remoteNodeResponse.ValidatorResponse = _convertValidatorEntryToResponse(utxoView, validatorEntry, params) } - return nil, nil + return remoteNodeResponse, nil } func (fes *APIServer) _handleConnectDeSoNode( From 0f202c41f9e3798370611347a621d08d918ca019 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Thu, 11 Apr 2024 20:15:53 -0400 Subject: [PATCH 80/84] trigger build 04-11-24 (#588) From d50b28a93ce546979589fb6186b1a1a53b61d5ad Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Fri, 12 Apr 2024 13:39:36 -0400 Subject: [PATCH 81/84] Empty commit to trigger CI From 758d4f81dc3d541646cadb6708a0c5e9c7f4649f Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 12 Apr 2024 13:54:49 -0400 Subject: [PATCH 82/84] Block until read only view regenerates in afterProcessSubmitPostTransaction (#590) --- routes/transaction.go | 1 + 1 file changed, 1 insertion(+) diff --git a/routes/transaction.go b/routes/transaction.go index e530e5a3..09700621 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -134,6 +134,7 @@ func (fes *APIServer) SubmitTransaction(ww http.ResponseWriter, req *http.Reques // 1. Attach the PostEntry to the response so the client can render it // 2. Attempt to auto-whitelist the post for the global feed func (fes *APIServer) _afterProcessSubmitPostTransaction(txn *lib.MsgDeSoTxn, response *SubmitTransactionResponse) error { + fes.backendServer.GetMempool().BlockUntilReadOnlyViewRegenerated() utxoView, err := fes.backendServer.GetMempool().GetAugmentedUniversalView() if err != nil { return errors.Errorf("Problem with GetAugmentedUniversalView: %v", err) From 15dcd32b022ad3bd2b5dccbcf559e7983c69f2a5 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Fri, 12 Apr 2024 14:29:51 -0400 Subject: [PATCH 83/84] Add LatestView to CheckpointBlockInfo endpoint (#589) --- routes/transaction.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/routes/transaction.go b/routes/transaction.go index 09700621..ee7c128e 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -4360,9 +4360,10 @@ func (fes *APIServer) GetCommittedTipBlockInfo(ww http.ResponseWriter, req *http } // Return the block tip. if err := json.NewEncoder(ww).Encode(&lib.CheckpointBlockInfo{ - Height: blockTip.Header.Height, - Hash: blockTip.Hash, - HashHex: blockTip.Hash.String(), + Height: blockTip.Header.Height, + Hash: blockTip.Hash, + HashHex: blockTip.Hash.String(), + LatestView: fes.backendServer.GetLatestView(), }); err != nil { _AddBadRequestError(ww, "GetCommittedTipBlockInfo: Problem encoding response as JSON: "+err.Error()) return From 5db55b6024b8390b585bfbbe69e2bef4283ae1f5 Mon Sep 17 00:00:00 2001 From: iamsofonias Date: Fri, 12 Apr 2024 16:02:29 -0400 Subject: [PATCH 84/84] Empty trigger for CI