From 58217f26c5e2a09e55123e18004f2c59d6a07a2c Mon Sep 17 00:00:00 2001 From: tokikuch Date: Mon, 25 Dec 2023 21:18:36 -0800 Subject: [PATCH] [v0.11 feature] Built-in Reward Share (#1581) ## Description This patch implements the Built-in Reward Share feature which lets the network itself to distribute the relay/block rewards into multiple addresses. The change consists of the following parts. - Add `RewardDelegators` in `Validator` - Add `RewardDelegators` in `MsgStake` - Add a new command `pocket nodes stakeNew` - Distributes the fee of claim/proof transaction to a node's operator address - Add a new config `prevent_negative_reward_claim` not to claim a potential loss evidence. This change is consensus-breaking. The new behavior is put behind a new feature key `RewardDelegator`. The new field is kept unavailable until activation. The new structure of `Validator` or `MsgStake` is backward/forward compatible, meaning the new binary can still unmarshal data marshaled by an older binary, and vice versa. In other words, the network before `RewardDelegator` activation accepts an `MsgStake` transaction, ignoring the `RewardDelegators` field. And the new `Validator` structure can handle all historical states from genesis. Therefore this patch does not introduce a structure like `10.0Validaor` as the NCUST patch did before. ### Summary generated by Reviewpad on 26 Dec 23 01:21 UTC This pull request includes changes to multiple files. Here is a summary of the diff: 1. The file `common_test.go` was modified to replace the import of `math/rand` with `crypto/rand`. Additionally, the comment `// : deadcode unused` was removed. 2. The file `x/nodes/keeper/abci_test.go` was modified to add and remove import statements, as well as comment out unnecessary code related to state conversion. 3. The file `x/nodes/types/validator.go` was modified to add an import, add a new field to the `Validator` struct, add a new function to create a validator from a message, modify several methods to include a new field in the output, and add a new struct and comment. 4. The file `x/nodes/types/validator_test.go` was modified to add import statements and a new test function. 5. The file `msg_test.go` was modified to add and remove import statements, add new test functions, and update existing test functions. 6. The file `keeper_test.go` was modified to add import statements, modify existing test functions, and add new test functions. 7. The file `go.mod` was modified to add and update package requirements. 8. The file `handler.go` was modified to add import statements and modify function implementations. 9. The file `nodes.proto` was modified to remove an import statement and add a new field to a message. 10. The file `msg.go` was modified to add import statements, add a new struct and function, and modify existing methods. 11. The file `genesis_test.go` was modified to add import statements and modify existing test functions. 12. The file `rpc_test.go` was modified to add and remove import statements, modify function implementations, and add test cases. 13. The file `expectedKeepers.go` was modified to remove comments and add a new method. 14. The file `config.go` was modified to add a new field to a struct. 15. The file `msg.proto` was modified to add a new field to a message. 16. The file `LegacyValidator.go` was modified to add a new method and update existing methods. 17. The file `errors.go` was modified to add new error codes and functions to handle them. 18. The file `reward_test.go` was modified to add import statements, add and update test functions. 19. The file `util_test.go` was modified to rearrange import statements and add new test functions. Please review these changes and provide any necessary feedback. Let me know if you need more information or if there's anything else I can assist you with. --------- Co-authored-by: tokikuch --- app/cmd/cli/node.go | 86 ++++++++ app/cmd/cli/txUtil.go | 84 +++++++ app/cmd/rpc/rpc_test.go | 123 ++++++++++- codec/codec.go | 7 + go.mod | 20 +- go.sum | 61 ++---- proto/x/nodes/msg.proto | 5 + proto/x/nodes/nodes.proto | 2 +- types/config.go | 1 + x/auth/types/txbuilder.go | 29 ++- x/nodes/genesis_test.go | 9 +- x/nodes/handler.go | 28 ++- x/nodes/keeper/abci_test.go | 6 +- x/nodes/keeper/common_test.go | 3 +- x/nodes/keeper/keeper.go | 24 -- x/nodes/keeper/params.go | 25 ++- x/nodes/keeper/reward.go | 238 ++++++++++++++++---- x/nodes/keeper/reward_test.go | 250 +++++++++++++++++++-- x/nodes/keeper/valStateChanges.go | 20 ++ x/nodes/keeper/valStateChanges_test.go | 106 ++++++++- x/nodes/keeper/validator.go | 9 +- x/nodes/keeper/validator_test.go | 72 +++++- x/nodes/types/errors.go | 66 +++--- x/nodes/types/expectedKeepers.go | 17 +- x/nodes/types/msg.go | 111 ++++++++-- x/nodes/types/msg.pb.go | 280 +++++++++++++++++------- x/nodes/types/msg_test.go | 51 ++++- x/nodes/types/nodes.pb.go | 290 ++++++++++++++++++------- x/nodes/types/params_test.go | 33 +-- x/nodes/types/util.go | 33 ++- x/nodes/types/util_test.go | 43 +++- x/nodes/types/validator.go | 62 +++++- x/nodes/types/validator_legacy.go | 38 +++- x/nodes/types/validator_test.go | 5 +- x/pocketcore/keeper/claim.go | 40 +++- x/pocketcore/types/expectedKeepers.go | 6 + x/pocketcore/types/service_test.go | 13 ++ 37 files changed, 1884 insertions(+), 412 deletions(-) diff --git a/app/cmd/cli/node.go b/app/cmd/cli/node.go index f9d9eeeeb..acb74c8bf 100644 --- a/app/cmd/cli/node.go +++ b/app/cmd/cli/node.go @@ -13,6 +13,7 @@ func init() { rootCmd.AddCommand(nodesCmd) nodesCmd.AddCommand(nodeUnstakeCmd) nodesCmd.AddCommand(nodeUnjailCmd) + nodesCmd.AddCommand(stakeNewCmd) } var nodesCmd = &cobra.Command{ @@ -116,3 +117,88 @@ Will prompt the user for the account passphrase.`, fmt.Println(resp) }, } + +// stakeNewCmd is an upgraded version of `nodesCmd` that captures newer +// on-chain functionality in a cleaner way +var stakeNewCmd = &cobra.Command{ + Use: "stakeNew [Memo]", + Short: "Stake a node in the network", + Long: `Stake a node in the network, promoting it to a servicer or a validator. + +The command takes the following parameters. + + OperatorPublicKey Public key to use as the node's operator account + OutputAddress Address to use as the node's output account + SignerAddress Address to sign the transaction + Stake Amount to stake in uPOKT + ChainIDs Comma-separated chain IDs to host on the node + ServiceURL Relay endpoint of the node. Must include the port number. + RewardDelegators Addresses to share rewards + NetworkID Network ID to submit a transaction to e.g. mainnet or testnet + Fee Transaction fee in uPOKT + Memo Optional. Text to include in the transaction. No functional effect. + +Example: +$ pocket nodes stakeNew \ + e237efc54a93ed61689959e9afa0d4bd49fa11c0b946c35e6bebaccb052ce3fc \ + fe818527cd743866c1db6bdeb18731d04891df78 \ + 1164b9c95638fc201f35eca2af4c35fe0a81b6cf \ + 8000000000000 \ + DEAD,BEEF \ + https://x.com:443 \ + '{"1000000000000000000000000000000000000000":1,"2000000000000000000000000000000000000000":2}' \ + mainnet \ + 10000 \ + "new stake with delegators!" +`, + Args: cobra.MinimumNArgs(9), + Run: func(cmd *cobra.Command, args []string) { + app.InitConfig(datadir, tmNode, persistentPeers, seeds, remoteCLIURL) + + operatorPubKey := args[0] + outputAddr := args[1] + signerAddr := args[2] + stakeAmount := args[3] + chains := args[4] + serviceUrl := args[5] + delegators := args[6] + networkId := args[7] + fee := args[8] + memo := "" + if len(args) >= 10 { + memo = args[9] + } + + fmt.Println("Enter Passphrase:") + passphrase := app.Credentials(pwd) + + rawStakeTx, err := BuildStakeTx( + operatorPubKey, + outputAddr, + stakeAmount, + chains, + serviceUrl, + delegators, + networkId, + fee, + memo, + signerAddr, + passphrase, + ) + if err != nil { + fmt.Println(err) + return + } + txBytes, err := json.Marshal(rawStakeTx) + if err != nil { + fmt.Println("Fail to build a transaction:", err) + return + } + resp, err := QueryRPC(SendRawTxPath, txBytes) + if err != nil { + fmt.Println("Fail to submit a transaction:", err) + return + } + fmt.Println(resp) + }, +} diff --git a/app/cmd/cli/txUtil.go b/app/cmd/cli/txUtil.go index 1985ec309..0bccd4943 100644 --- a/app/cmd/cli/txUtil.go +++ b/app/cmd/cli/txUtil.go @@ -5,6 +5,8 @@ import ( "encoding/json" "errors" "fmt" + "strconv" + "strings" "github.com/pokt-network/pocket-core/app" "github.com/pokt-network/pocket-core/app/cmd/rpc" @@ -251,6 +253,88 @@ func StakeNode(chains []string, serviceURL, operatorPubKey, output, passphrase, }, nil } +func BuildStakeTx( + operatorPubKeyStr, + outputAddrStr, + stakeAmountStr, + chains, + serviceUrl, + delegatorsStr, + networkId, + feeStr, + memo, + signerAddrStr, + passphrase string, +) (*rpc.SendRawTxParams, error) { + keybase, err := app.GetKeybase() + if err != nil { + return nil, err + } + + signerAddr, err := sdk.AddressFromHex(signerAddrStr) + if err != nil { + return nil, err + } + + operatorPubkey, err := crypto.NewPublicKey(operatorPubKeyStr) + if err != nil { + return nil, err + } + + outputAddr, err := sdk.AddressFromHex(outputAddrStr) + if err != nil { + return nil, err + } + + stakeAmount, ok := sdk.NewIntFromString(stakeAmountStr) + if !ok { + return nil, errors.New("Invalid stake amount: " + stakeAmountStr) + } + + fee, err := strconv.ParseInt(feeStr, 10, 64) + if err != nil { + return nil, err + } + + msg := &nodeTypes.MsgStake{ + PublicKey: operatorPubkey, + Chains: strings.Split(chains, ","), + Value: stakeAmount, + ServiceUrl: serviceUrl, + Output: outputAddr, + } + + if len(delegatorsStr) > 0 { + if json.Unmarshal([]byte(delegatorsStr), &msg.RewardDelegators); err != nil { + return nil, err + } + } + + if err = msg.ValidateBasic(); err != nil { + return nil, err + } + + txBz, err := newTxBz( + app.Codec(), + msg, + signerAddr, + networkId, + keybase, + passphrase, + fee, + memo, + false, + ) + if err != nil { + return nil, err + } + + return &rpc.SendRawTxParams{ + Addr: signerAddrStr, + RawHexBytes: hex.EncodeToString(txBz), + }, nil +} + // UnstakeNode - start unstaking message to node func UnstakeNode(operatorAddr, fromAddr, passphrase, chainID string, fees int64, isBefore8 bool) (*rpc.SendRawTxParams, error) { fa, err := sdk.AddressFromHex(fromAddr) diff --git a/app/cmd/rpc/rpc_test.go b/app/cmd/rpc/rpc_test.go index f2c71d026..dd53771ac 100644 --- a/app/cmd/rpc/rpc_test.go +++ b/app/cmd/rpc/rpc_test.go @@ -2,11 +2,11 @@ package rpc import ( "bytes" + "encoding/base64" "encoding/hex" "encoding/json" "fmt" "io" - "io/ioutil" "math/rand" "net/http" "net/http/httptest" @@ -16,22 +16,20 @@ import ( "sync" "testing" + "github.com/julienschmidt/httprouter" "github.com/pokt-network/pocket-core/app" "github.com/pokt-network/pocket-core/codec" "github.com/pokt-network/pocket-core/crypto" - rand2 "github.com/tendermint/tendermint/libs/rand" - "github.com/tendermint/tendermint/rpc/client" - - types3 "github.com/pokt-network/pocket-core/x/apps/types" - - "github.com/julienschmidt/httprouter" "github.com/pokt-network/pocket-core/types" + types3 "github.com/pokt-network/pocket-core/x/apps/types" "github.com/pokt-network/pocket-core/x/auth" authTypes "github.com/pokt-network/pocket-core/x/auth/types" "github.com/pokt-network/pocket-core/x/nodes" types2 "github.com/pokt-network/pocket-core/x/nodes/types" pocketTypes "github.com/pokt-network/pocket-core/x/pocketcore/types" "github.com/stretchr/testify/assert" + rand2 "github.com/tendermint/tendermint/libs/rand" + "github.com/tendermint/tendermint/rpc/client" core_types "github.com/tendermint/tendermint/rpc/core/types" tmTypes "github.com/tendermint/tendermint/types" "gopkg.in/h2non/gock.v1" @@ -269,6 +267,14 @@ func TestRPC_QueryUnconfirmedTxs(t *testing.T) { totalCountTxs, _ := resTXs.TotalTxs.Int64() assert.Equal(t, pageCount, int64(1)) + + if totalCountTxs < int64(totalTxs) { + t.Skipf( + `totalCountTxs was %v. Probably this is a timing issue that one tx was +processed before UnconfirmedTxs. Skipping the test for now.`, + totalCountTxs, + ) + } assert.Equal(t, totalCountTxs, int64(totalTxs)) for _, resTX := range resTXs.Txs { @@ -1473,7 +1479,7 @@ func newQueryRequest(query string, body io.Reader) *http.Request { func getResponse(rec *httptest.ResponseRecorder) string { res := rec.Result() defer res.Body.Close() - b, err := ioutil.ReadAll(res.Body) + b, err := io.ReadAll(res.Body) if err != nil { fmt.Println("could not read response: " + err.Error()) return "" @@ -1493,7 +1499,7 @@ func getResponse(rec *httptest.ResponseRecorder) string { func getJSONResponse(rec *httptest.ResponseRecorder) []byte { res := rec.Result() defer res.Body.Close() - b, err := ioutil.ReadAll(res.Body) + b, err := io.ReadAll(res.Body) if err != nil { panic("could not read response: " + err.Error()) } @@ -1636,3 +1642,102 @@ func NewValidChallengeProof(t *testing.T, privateKeys []crypto.PrivateKey) (chal } return proof } + +func generateTestTx() (string, error) { + app.Codec() + privKey, err := crypto.NewPrivateKey("5d86a93dee1ef5f950ccfaafd09d9c812f790c3b2c07945501f68b339118aca0e237efc54a93ed61689959e9afa0d4bd49fa11c0b946c35e6bebaccb052ce3fc") + if err != nil { + return "", err + } + outputAddr, err := types.AddressFromHex("fe818527cd743866c1db6bdeb18731d04891df78") + if err != nil { + return "", err + } + msg := &types2.MsgStake{ + PublicKey: privKey.PublicKey(), + Chains: []string{"DEAD", "BEEF"}, + Value: types.NewInt(8000000000000), + ServiceUrl: "https://x.com:443", + Output: outputAddr, + RewardDelegators: map[string]uint32{ + "1000000000000000000000000000000000000000": 1, + "2000000000000000000000000000000000000000": 2, + }, + } + builder := authTypes.NewTxBuilder( + auth.DefaultTxEncoder(app.Codec()), + auth.DefaultTxDecoder(app.Codec()), + "mainnet", + "memo", + types.NewCoins(types.NewCoin(types.DefaultStakeDenom, types.NewInt(10000))), + ) + entropy := int64(42) + txBytes, err := builder.BuildAndSignWithEntropyForTesting(privKey, msg, entropy) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(txBytes), nil +} + +// TestMsgStake_Marshaling_BackwardCompatibility verifies MsgStake +// has backward compatibility before/after the Delegators upgrade, +// meaning this test passes without the Delegators patch. +func TestMsgStake_Marshaling_BackwardCompatibility(t *testing.T) { + // StakeTxBeforeDelegatorsUpgrade is a transaction in Pocket Mainnet. + // You can get this with the following command. + // + // $ curl -s -X POST -H "Content-Type: application/json" \ + // -d '{"hash":"3640B15041998FE800C2F61FC033CBF295D9282B5E7045A16F754ED9D8A54AFF"}' \ + // /v1/query/tx | jq '.tx' + StakeTxBeforeDelegatorsUpgrade := + "/wIK4QEKFy94Lm5vZGVzLk1zZ1Byb3RvU3Rha2U4EsUBCiBzfNC5BqUX6Aow9768" + + "QTKyYiRdhqrGqeqTIMVSckAe8RIEMDAwMxIEMDAwNBIEMDAwNRIEMDAwORIEMDAy" + + "MRIEMDAyNxIEMDAyOBIEMDA0NhIEMDA0NxIEMDA0ORIEMDA1MBIEMDA1NhIEMDA2" + + "NhIEMDA3MhIEMDNERhoMMTQwMDAwMDAwMDAwIiNodHRwczovL3ZhbDE2NjcwMDUy" + + "MDYuYzBkM3Iub3JnOjQ0MyoU6By0i9H9b2jibqTioCbqBdSFO3USDgoFdXBva3QS" + + "BTEwMDAwGmQKIHN80LkGpRfoCjD3vrxBMrJiJF2Gqsap6pMgxVJyQB7xEkDOrzwH" + + "w68+vl2z9nC+zYz3u4J7Oe3ntBOVP+cYHO5+lLuc8nH0OaG6pujXEPo19F5qW4Zh" + + "NBEgtChJp+QhYVgIIiBDdXN0b2RpYWwgdG8gTm9uLUN1c3RvZGlhbCBhZ2FpbijS" + + "CQ==" + // StakeTxBeforeDelegatorsUpgrade is a transaction with the Delegators field. + // You can generate this transaction by uncommenting the following two lines. + // StakeTxAfterDelegatorsUpgrade, err := generateTestTx() + // assert.Nil(t, err) + StakeTxAfterDelegatorsUpgrade := + "3wIK3gEKFy94Lm5vZGVzLk1zZ1Byb3RvU3Rha2U4EsIBCiDiN+/FSpPtYWiZWemv" + + "oNS9SfoRwLlGw15r66zLBSzj/BIEREVBRBIEQkVFRhoNODAwMDAwMDAwMDAwMCIR" + + "aHR0cHM6Ly94LmNvbTo0NDMqFP6BhSfNdDhmwdtr3rGHMdBIkd94MiwKKDIwMDAw" + + "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAQAjIsCigxMDAwMDAw" + + "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwEAESDgoFdXBva3QSBTEw" + + "MDAwGmQKIOI378VKk+1haJlZ6a+g1L1J+hHAuUbDXmvrrMsFLOP8EkDKz4AcELVB" + + "8Lyzi0+MVD/KXDIlTqjNLlBvFzOen7kZpR1it6gD79SLJXfWhB0qeu7Bux2VWQyf" + + "2wBBckGpIesBIgRtZW1vKCo=" + + originalNCUST := codec.UpgradeFeatureMap[codec.NonCustodialUpdateKey] + t.Cleanup(func() { + codec.UpgradeFeatureMap[codec.NonCustodialUpdateKey] = originalNCUST + }) + + // Choose Proto marshaler + heightForProto := int64(-1) + // Simulate post-NCUST + codec.UpgradeFeatureMap[codec.NonCustodialUpdateKey] = -1 + // Initialize app.cdc + app.Codec() + + // Validate that an old stake messages DOES NOT have delegators + stdTx, err := app.UnmarshalTxStr(StakeTxBeforeDelegatorsUpgrade, heightForProto) + assert.Nil(t, err) + msgStake, ok := stdTx.Msg.(*types2.MsgStake) + assert.True(t, ok) + assert.Nil(t, msgStake.RewardDelegators) + assert.Nil(t, msgStake.ValidateBasic()) + + // Validate that an old stake messages DOES have delegators + stdTx, err = app.UnmarshalTxStr(StakeTxAfterDelegatorsUpgrade, heightForProto) + assert.Nil(t, err) + msgStake, ok = stdTx.Msg.(*types2.MsgStake) + assert.True(t, ok) + assert.NotNil(t, msgStake.RewardDelegators) + assert.Nil(t, msgStake.ValidateBasic()) +} diff --git a/codec/codec.go b/codec/codec.go index 79f24db70..a211337a7 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -60,6 +60,7 @@ const ( ClearUnjailedValSessionKey = "CRVAL" PerChainRTTM = "PerChainRTTM" AppTransferKey = "AppTransfer" + RewardDelegatorsKey = "RewardDelegators" ) func GetCodecUpgradeHeight() int64 { @@ -294,6 +295,12 @@ func (cdc *Codec) IsAfterAppTransferUpgrade(height int64) bool { TestMode <= -3 } +func (cdc *Codec) IsAfterRewardDelegatorUpgrade(height int64) bool { + return (UpgradeFeatureMap[RewardDelegatorsKey] != 0 && + height >= UpgradeFeatureMap[RewardDelegatorsKey]) || + TestMode <= -3 +} + // IsOnNonCustodialUpgrade Note: includes the actual upgrade height func (cdc *Codec) IsOnNonCustodialUpgrade(height int64) bool { return (UpgradeFeatureMap[NonCustodialUpdateKey] != 0 && height == UpgradeFeatureMap[NonCustodialUpdateKey]) || TestMode <= -3 diff --git a/go.mod b/go.mod index 3ce9d3f65..6fd567dbb 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,11 @@ replace github.com/tendermint/tendermint => github.com/pokt-network/tendermint v replace github.com/tendermint/tm-db => github.com/pokt-network/tm-db v0.5.2-0.20220118210553-9b2300f289ba require ( + github.com/cosmos/gogoproto v1.4.10 github.com/cucumber/godog v0.12.5 github.com/go-kit/kit v0.12.0 github.com/gogo/protobuf v1.3.2 - github.com/golang/protobuf v1.5.2 + github.com/golang/protobuf v1.5.3 github.com/hashicorp/golang-lru v0.5.4 github.com/jordanorelli/lexnum v0.0.0-20141216151731-460eeb125754 github.com/julienschmidt/httprouter v1.3.0 @@ -25,7 +26,7 @@ require ( github.com/tendermint/tm-db v0.5.1 github.com/willf/bloom v2.0.3+incompatible golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 - google.golang.org/protobuf v1.27.1 + google.golang.org/protobuf v1.30.0 gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 ) @@ -35,7 +36,7 @@ require ( github.com/Workiva/go-datastructures v1.0.52 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd v0.20.1-beta // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect github.com/cucumber/gherkin-go/v19 v19.0.3 // indirect github.com/cucumber/messages-go/v16 v16.0.1 // indirect @@ -45,7 +46,7 @@ require ( github.com/gofrs/uuid v4.0.0+incompatible // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.0.0 // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect @@ -73,11 +74,12 @@ require ( github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/willf/bitset v1.1.10 // indirect go.etcd.io/bbolt v1.3.3 // indirect - golang.org/x/net v0.1.0 // indirect + golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 // indirect + golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.1.0 // indirect - golang.org/x/text v0.4.0 // indirect - google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4 // indirect - google.golang.org/grpc v1.40.0 // indirect + golang.org/x/term v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.55.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 74845e4f7..806724adb 100644 --- a/go.sum +++ b/go.sum @@ -47,7 +47,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 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= @@ -71,15 +70,13 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 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.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 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= @@ -87,6 +84,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= +github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= 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.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -106,8 +105,6 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -174,8 +171,9 @@ 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/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -191,8 +189,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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 v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -206,7 +204,6 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf 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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -216,7 +213,6 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad 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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= @@ -378,7 +374,6 @@ github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqn github.com/regen-network/cosmos-proto v0.3.0 h1:24dVpPrPi0GDoPVLesf2Ug98iK5QgVscPl0ga4Eoub0= github.com/regen-network/cosmos-proto v0.3.0/go.mod h1:zuP2jVPHab6+IIyOx3nXHFN+euFNeS3W8XQkcdd4s7A= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -435,7 +430,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de 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= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -444,7 +438,6 @@ 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.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 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= @@ -469,6 +462,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 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/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE= +golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 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= @@ -481,7 +476,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl 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-20210508222113-6edffad5e616/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/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -490,7 +484,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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= @@ -526,11 +519,10 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R 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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= 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= @@ -547,7 +539,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ 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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -593,24 +584,21 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/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-20210423082822-04245dca01da/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-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.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.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= 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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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= @@ -661,7 +649,6 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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= @@ -712,15 +699,14 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG 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-20200513103714-09dca8ec2884/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-20210917145530-b395a37504d4 h1:ysnBoUyeL/H6RCvNRhWHjKoDEmguI+mPU+qHgK8qv/w= -google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= 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= @@ -733,10 +719,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa 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.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= 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= @@ -749,8 +733,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj 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.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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= @@ -768,7 +752,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD 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.3/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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/proto/x/nodes/msg.proto b/proto/x/nodes/msg.proto index 46d42b10b..8e0a49d84 100755 --- a/proto/x/nodes/msg.proto +++ b/proto/x/nodes/msg.proto @@ -23,6 +23,11 @@ message MsgProtoStake { (gogoproto.jsontag) = "output_address,omitempty", (gogoproto.moretags) = "yaml:\"output_address\"" ]; + // Mapping from delegated-to addresses to a percentage of rewards. + map RewardDelegators = 6 [ + (gogoproto.jsontag) = "reward_delegators,omitempty", + (gogoproto.moretags) = "yaml:\"reward_delegators\"" + ]; } message LegacyMsgProtoStake { diff --git a/proto/x/nodes/nodes.proto b/proto/x/nodes/nodes.proto index 2a0d49b49..58ddf12bf 100755 --- a/proto/x/nodes/nodes.proto +++ b/proto/x/nodes/nodes.proto @@ -3,7 +3,6 @@ package x.nodes; import "gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; -import "google/protobuf/duration.proto"; option go_package = "github.com/pokt-network/pocket-core/x/nodes/types"; @@ -21,6 +20,7 @@ message ProtoValidator { string StakedTokens = 7 [(gogoproto.customtype) = "github.com/pokt-network/pocket-core/types.BigInt", (gogoproto.jsontag) = "tokens", (gogoproto.nullable) = false]; google.protobuf.Timestamp UnstakingCompletionTime = 8 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.jsontag) = "unstaking_time", (gogoproto.moretags) = "yaml:\"unstaking_time\""]; bytes OutputAddress = 9 [(gogoproto.casttype) = "github.com/pokt-network/pocket-core/types.Address", (gogoproto.jsontag) = "output_address,omitempty", (gogoproto.moretags) = "yaml:\"output_address\""]; + map RewardDelegators = 10 [(gogoproto.jsontag) = "reward_delegators,omitempty", (gogoproto.moretags) = "yaml:\"reward_delegators\""]; } message LegacyProtoValidator { diff --git a/types/config.go b/types/config.go index 05a5190e4..700142da8 100644 --- a/types/config.go +++ b/types/config.go @@ -50,6 +50,7 @@ type PocketConfig struct { GenerateTokenOnStart bool `json:"generate_token_on_start"` LeanPocket bool `json:"lean_pocket"` LeanPocketUserKeyFileName string `json:"lean_pocket_user_key_file"` + PreventNegativeRewardClaim bool `json:"prevent_negative_reward_claim"` } func (c PocketConfig) GetLeanPocketUserKeyFilePath() string { diff --git a/x/auth/types/txbuilder.go b/x/auth/types/txbuilder.go index 38be47e77..98fd14837 100644 --- a/x/auth/types/txbuilder.go +++ b/x/auth/types/txbuilder.go @@ -3,13 +3,12 @@ package types import ( "errors" "fmt" - "github.com/tendermint/tendermint/libs/rand" "strings" "github.com/pokt-network/pocket-core/crypto" - crkeys "github.com/pokt-network/pocket-core/crypto/keys" sdk "github.com/pokt-network/pocket-core/types" + "github.com/tendermint/tendermint/libs/rand" ) // TxBuilder implements a transaction context created in SDK modules. @@ -113,6 +112,32 @@ func (bldr TxBuilder) BuildAndSign(address sdk.Address, privateKey crypto.Privat return bldr.txEncoder(NewTx(msg, bldr.fees, sig, bldr.memo, entropy), -1) } +// BuildAndSignWithEntropyForTesting signs a given message with a given +// private key and entropy. +// This is for testing use only. Use BuildAndSign for production use. +func (bldr TxBuilder) BuildAndSignWithEntropyForTesting( + privateKey crypto.PrivateKey, + msg sdk.ProtoMsg, + entropy int64, +) ([]byte, error) { + if bldr.chainID == "" { + return nil, errors.New("cant build and sign transaciton: the chainID is empty") + } + bytesToSign, err := StdSignBytes(bldr.chainID, entropy, bldr.fees, msg, bldr.memo) + if err != nil { + return nil, err + } + sigBytes, err := privateKey.Sign(bytesToSign) + if err != nil { + return nil, err + } + sig := StdSignature{ + Signature: sigBytes, + PublicKey: privateKey.PublicKey(), + } + return bldr.txEncoder(NewTx(msg, bldr.fees, sig, bldr.memo, entropy), -1) +} + // BuildAndSignWithKeyBase builds a single message to be signed, and signs a transaction // with the built message given a address, passphrase, and a set of messages. func (bldr TxBuilder) BuildAndSignWithKeyBase(address sdk.Address, passphrase string, msg sdk.ProtoMsg, legacyCodec bool) ([]byte, error) { diff --git a/x/nodes/genesis_test.go b/x/nodes/genesis_test.go index 2ad2d8bb8..75138cd88 100644 --- a/x/nodes/genesis_test.go +++ b/x/nodes/genesis_test.go @@ -1,13 +1,14 @@ package nodes import ( + "reflect" + "testing" + "time" + sdk "github.com/pokt-network/pocket-core/types" "github.com/pokt-network/pocket-core/x/nodes/keeper" "github.com/pokt-network/pocket-core/x/nodes/types" abci "github.com/tendermint/tendermint/abci/types" - "reflect" - "testing" - "time" ) func TestExportGenesis(t *testing.T) { @@ -99,7 +100,7 @@ func TestValidateGenesis(t *testing.T) { {"Test ValidateGenesis 5", args{data: datafortest5}, true}, {"Test ValidateGenesis 6", args{data: datafortest6}, true}, {"Test ValidateGenesis 7", args{data: datafortest7}, true}, - {"Test ValidateGenesis 8", args{data: datafortest8}, true}, + {"Test ValidateGenesis 8", args{data: datafortest8}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/x/nodes/handler.go b/x/nodes/handler.go index 99dfcdea8..37ec16422 100644 --- a/x/nodes/handler.go +++ b/x/nodes/handler.go @@ -2,12 +2,13 @@ package nodes import ( "fmt" + "reflect" + "time" + "github.com/pokt-network/pocket-core/crypto" sdk "github.com/pokt-network/pocket-core/types" "github.com/pokt-network/pocket-core/x/nodes/keeper" "github.com/pokt-network/pocket-core/x/nodes/types" - "reflect" - "time" ) func NewHandler(k keeper.Keeper) sdk.Handler { @@ -59,10 +60,21 @@ func handleStake(ctx sdk.Ctx, msg types.MsgStake, k keeper.Keeper, signer crypto } } - pk := msg.PublicKey - addr := pk.Address() - // create validator object using the message fields - validator := types.NewValidator(sdk.Address(addr), pk, msg.Chains, msg.ServiceUrl, sdk.ZeroInt(), msg.Output) + if k.Cdc.IsAfterRewardDelegatorUpgrade(ctx.BlockHeight()) { + if err := msg.CheckRewardDelegators(); err != nil { + return err.Result() + } + } else if msg.RewardDelegators != nil { + // Ignore the delegators field before the upgrade + msg.RewardDelegators = nil + } + + validator := types.NewValidatorFromMsg(msg) + // We used to use NewValidator to initialize the `validator` that does not + // set the field StakedTokens. On the other hand, NewValidatorFromMsg sets + // the field StakedTokens. To keep the same behavior, we reset StakedTokens + // to 0 and leave StakedTokens to be set through StakeValidator below. + validator.StakedTokens = sdk.ZeroInt() // check if they can stake if err := k.ValidateValidatorStaking(ctx, validator, msg.Value, sdk.Address(signer.Address())); err != nil { if sdk.ShowTimeTrackData { @@ -85,13 +97,13 @@ func handleStake(ctx sdk.Ctx, msg types.MsgStake, k keeper.Keeper, signer crypto sdk.NewEvent( types.EventTypeStake, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, sdk.Address(addr).String()), + sdk.NewAttribute(sdk.AttributeKeySender, validator.Address.String()), sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Value.String()), ), sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, sdk.Address(addr).String()), + sdk.NewAttribute(sdk.AttributeKeySender, validator.Address.String()), ), }) return sdk.Result{Events: ctx.EventManager().Events()} diff --git a/x/nodes/keeper/abci_test.go b/x/nodes/keeper/abci_test.go index 1a56c5bff..cf245c679 100644 --- a/x/nodes/keeper/abci_test.go +++ b/x/nodes/keeper/abci_test.go @@ -1,11 +1,12 @@ package keeper import ( + "testing" + sdk "github.com/pokt-network/pocket-core/types" "github.com/pokt-network/pocket-core/x/nodes/types" "github.com/stretchr/testify/assert" abci "github.com/tendermint/tendermint/abci/types" - "testing" ) func TestBeginBlocker(t *testing.T) { @@ -61,9 +62,6 @@ func TestKeeper_ConvertValidatorsState(t *testing.T) { ctx.Logger().Error("could not marshal validator: " + err.Error()) } err = store.Set(types.KeyForValByAllVals(lv.Address), bz) - // convert the state, can be commented out as not needed, - //intentionally left here as a reminder that state convert for this was planned but not needed and can be removed next version - //k.ConvertValidatorsState(ctx) // manually get validators using new structure value, err := store.Get(types.KeyForValByAllVals(lv.Address)) assert.Nil(t, err) diff --git a/x/nodes/keeper/common_test.go b/x/nodes/keeper/common_test.go index 5baeed852..61fe0f69e 100644 --- a/x/nodes/keeper/common_test.go +++ b/x/nodes/keeper/common_test.go @@ -1,7 +1,7 @@ package keeper import ( - "math/rand" + "crypto/rand" "testing" "github.com/pokt-network/pocket-core/codec" @@ -28,7 +28,6 @@ var ( ) ) -// : deadcode unused // create a codec used only for testing func makeTestCodec() *codec.Codec { var cdc = codec.NewCodec(types2.NewInterfaceRegistry()) diff --git a/x/nodes/keeper/keeper.go b/x/nodes/keeper/keeper.go index 5c8ba326c..0b0c962c6 100644 --- a/x/nodes/keeper/keeper.go +++ b/x/nodes/keeper/keeper.go @@ -61,30 +61,6 @@ func (k Keeper) UpgradeCodec(ctx sdk.Ctx) { } } -func (k Keeper) ConvertValidatorsState(ctx sdk.Ctx) { - validators := make([]types.Validator, 0) - store := ctx.KVStore(k.storeKey) - iterator, _ := sdk.KVStorePrefixIterator(store, types.AllValidatorsKey) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - vl := &types.LegacyValidator{} - v := &types.Validator{} - err := k.Cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &vl, ctx.BlockHeight()) - if err != nil { - ctx.Logger().Error("could not unmarshal validator in ConvertValidtorState(): " + err.Error()) - err := k.Cdc.UnmarshalBinaryLengthPrefixed(iterator.Value(), &v, ctx.BlockHeight()) - if err == nil { - ctx.Logger().Error("Already new validator in ConvertValidtorState(): " + err.Error()) - } - continue - } - validators = append(validators, vl.ToValidator()) - } - for _, val := range validators { - k.SetValidator(ctx, val) - } -} - func (k Keeper) ConvertState(ctx sdk.Ctx) { k.Cdc.SetUpgradeOverride(false) params := k.GetParams(ctx) diff --git a/x/nodes/keeper/params.go b/x/nodes/keeper/params.go index 8702d2092..c410ce897 100644 --- a/x/nodes/keeper/params.go +++ b/x/nodes/keeper/params.go @@ -144,7 +144,11 @@ func (k Keeper) ServicerStakeFloorMultiplierExponent(ctx sdk.Ctx) (res sdk.BigDe return } -func (k Keeper) NodeReward(ctx sdk.Ctx, reward sdk.BigInt) (nodeReward sdk.BigInt, feesCollected sdk.BigInt) { +// Split block rewards into the node's cut and the feeCollector's (DAO + Proposer) cut +func (k Keeper) splitRewards( + ctx sdk.Ctx, + reward sdk.BigInt, +) (nodeReward, feesCollected sdk.BigInt) { // convert reward to dec r := reward.ToDec() // get the dao and proposer % ex DAO .1 or 10% Proposer .01 or 1% @@ -160,6 +164,25 @@ func (k Keeper) NodeReward(ctx sdk.Ctx, reward sdk.BigInt) (nodeReward sdk.BigIn return } +// Split feeCollector's cut into the DAO's cut and the Proposer's cut +func (k Keeper) splitFeesCollected( + ctx sdk.Ctx, + feesCollected sdk.BigInt, +) (daoCut, proposerCut sdk.BigInt) { + daoAllocation := sdk.NewDec(k.DAOAllocation(ctx)) + proposerAllocation := sdk.NewDec(k.ProposerAllocation(ctx)) + + // get the new percentages of `dao / (dao + proposer)` + daoAllocation = daoAllocation.Quo(daoAllocation.Add(proposerAllocation)) + + // dao cut calculation truncates int ex: 1.99uPOKT = 1uPOKT + daoCut = feesCollected.ToDec().Mul(daoAllocation).TruncateInt() + + // proposer gets whatever is left after the DAO's truncated rewards are taken out + proposerCut = feesCollected.Sub(daoCut) + return +} + // DAOAllocation - Retrieve DAO allocation func (k Keeper) DAOAllocation(ctx sdk.Ctx) (res int64) { k.Paramstore.Get(ctx, types.KeyDAOAllocation, &res) diff --git a/x/nodes/keeper/reward.go b/x/nodes/keeper/reward.go index 129cfc203..58121b60a 100644 --- a/x/nodes/keeper/reward.go +++ b/x/nodes/keeper/reward.go @@ -1,19 +1,82 @@ package keeper import ( + "encoding/json" + "errors" "fmt" "github.com/pokt-network/pocket-core/codec" sdk "github.com/pokt-network/pocket-core/types" govTypes "github.com/pokt-network/pocket-core/x/gov/types" "github.com/pokt-network/pocket-core/x/nodes/types" + pcTypes "github.com/pokt-network/pocket-core/x/pocketcore/types" + "github.com/tendermint/tendermint/libs/log" ) +// GetRewardCost - The cost a servicer needs to pay to earn relay rewards +func (k Keeper) GetRewardCost(ctx sdk.Ctx) sdk.BigInt { + return k.AccountKeeper.GetFee(ctx, pcTypes.MsgClaim{}). + Add(k.AccountKeeper.GetFee(ctx, pcTypes.MsgProof{})) +} + // RewardForRelays - Award coins to an address using the default multiplier func (k Keeper) RewardForRelays(ctx sdk.Ctx, relays sdk.BigInt, address sdk.Address) sdk.BigInt { return k.RewardForRelaysPerChain(ctx, "", relays, address) } +func (k Keeper) calculateRewardRewardPip22( + ctx sdk.Ctx, + relays, stake, multiplier sdk.BigInt, +) sdk.BigInt { + // floorstake to the lowest bin multiple or take ceiling, whichever is smaller + flooredStake := sdk.MinInt( + stake.Sub(stake.Mod(k.ServicerStakeFloorMultiplier(ctx))), + k.ServicerStakeWeightCeiling(ctx). + Sub(k.ServicerStakeWeightCeiling(ctx). + Mod(k.ServicerStakeFloorMultiplier(ctx))), + ) + // Convert from tokens to a BIN number + bin := flooredStake.Quo(k.ServicerStakeFloorMultiplier(ctx)) + // calculate the weight value, weight will be a floatng point number so cast + // to DEC here and then truncate back to big int + weight := bin.ToDec(). + FracPow( + k.ServicerStakeFloorMultiplierExponent(ctx), + Pip22ExponentDenominator, + ). + Quo(k.ServicerStakeWeightMultiplier(ctx)) + coinsDecimal := multiplier.ToDec().Mul(relays.ToDec()).Mul(weight) + // truncate back to int + return coinsDecimal.TruncateInt() +} + +// CalculateRelayReward - Calculates the amount of rewards based on the given +// number of relays and the staked tokens, and splits it to the servicer's cut +// and the DAO & Proposer cut. +func (k Keeper) CalculateRelayReward( + ctx sdk.Ctx, + chain string, + relays sdk.BigInt, + stake sdk.BigInt, +) (nodeReward, feesCollected sdk.BigInt) { + isAfterRSCAL := k.Cdc.IsAfterNamedFeatureActivationHeight( + ctx.BlockHeight(), + codec.RSCALKey, + ) + multiplier := k.GetChainSpecificMultiplier(ctx, chain) + + var coins sdk.BigInt + if isAfterRSCAL { + // scale the rewards if PIP22 is enabled + coins = k.calculateRewardRewardPip22(ctx, relays, stake, multiplier) + } else { + // otherwise just apply rttm + coins = multiplier.Mul(relays) + } + + return k.splitRewards(ctx, coins) +} + // RewardForRelaysPerChain - Award coins to an address for relays of a specific chain func (k Keeper) RewardForRelaysPerChain(ctx sdk.Ctx, chain string, relays sdk.BigInt, address sdk.Address) sdk.BigInt { // feature flags @@ -28,7 +91,11 @@ func (k Keeper) RewardForRelaysPerChain(ctx sdk.Ctx, chain string, relays sdk.Bi //adding "&& (isAfterRSCAL || isAfterNonCustodial)" to sync from scratch as weighted stake and non-custodial introduced this requirement if !found && (isAfterRSCAL || isNonCustodialActive) { - ctx.Logger().Error(fmt.Errorf("no validator found for address %s; at height %d\n", address.String(), ctx.BlockHeight()).Error()) + ctx.Logger().Error( + "no validator found", + "address", address, + "height", ctx.BlockHeight(), + ) return sdk.ZeroInt() } @@ -45,41 +112,104 @@ func (k Keeper) RewardForRelaysPerChain(ctx sdk.Ctx, chain string, relays sdk.Bi if isDuringFirstNonCustodialIssue { _, found := k.GetValidator(ctx, address) if !found { - ctx.Logger().Error(fmt.Errorf("no validator found for address %s; at height %d\n", address.String(), ctx.BlockHeight()).Error()) + ctx.Logger().Error( + "no validator found", + "address", address, + "height", ctx.BlockHeight(), + ) return sdk.ZeroInt() } } - multiplier := k.GetChainSpecificMultiplier(ctx, chain) - - var coins sdk.BigInt + toNode, toFeeCollector := + k.CalculateRelayReward(ctx, chain, relays, validator.GetTokens()) - //check if PIP22 is enabled, if so scale the rewards - if isAfterRSCAL { - stake := validator.GetTokens() - //floorstake to the lowest bin multiple or take ceiling, whicherver is smaller - flooredStake := sdk.MinInt(stake.Sub(stake.Mod(k.ServicerStakeFloorMultiplier(ctx))), k.ServicerStakeWeightCeiling(ctx).Sub(k.ServicerStakeWeightCeiling(ctx).Mod(k.ServicerStakeFloorMultiplier(ctx)))) - //Convert from tokens to a BIN number - bin := flooredStake.Quo(k.ServicerStakeFloorMultiplier(ctx)) - //calculate the weight value, weight will be a floatng point number so cast to DEC here and then truncate back to big int - weight := bin.ToDec().FracPow(k.ServicerStakeFloorMultiplierExponent(ctx), Pip22ExponentDenominator).Quo(k.ServicerStakeWeightMultiplier(ctx)) - coinsDecimal := multiplier.ToDec().Mul(relays.ToDec()).Mul(weight) - //truncate back to int - coins = coinsDecimal.TruncateInt() - } else { - coins = multiplier.Mul(relays) + // After the delegator upgrade, we compensate a servicer's operator wallet + // for the transaction fee of claim and proof. + if k.Cdc.IsAfterRewardDelegatorUpgrade(ctx.BlockHeight()) { + rewardCost := k.GetRewardCost(ctx) + if toNode.LT(rewardCost) { + // If the servicer's portion is less than the reward cost, we send + // all of the servicer's portion to the servicer and no reward is sent + // to the output address or delegators. This case causes a net loss to + // the servicer. If prevent_negative_reward_claim is set to true, + // a servicer will not claim for tiny evidences that cause a net loss. + rewardCost = toNode + } + if rewardCost.IsPositive() { + k.mint(ctx, rewardCost, validator.Address) + toNode = toNode.Sub(rewardCost) + } } - toNode, toFeeCollector := k.NodeReward(ctx, coins) - if toNode.IsPositive() { - k.mint(ctx, toNode, address) + err := SplitNodeRewards( + ctx.Logger(), + toNode, + address, + validator.RewardDelegators, + func(recipient sdk.Address, share sdk.BigInt) { + k.mint(ctx, share, recipient) + }, + ) + if err != nil { + ctx.Logger().Error("unable to split relay rewards", + "height", ctx.BlockHeight(), + "servicer", validator.Address, + "err", err.Error(), + ) } + if toFeeCollector.IsPositive() { k.mint(ctx, toFeeCollector, k.getFeePool(ctx).GetAddress()) } return toNode } +// Splits rewards into the primary recipient and delegator addresses and +// invokes a callback per share. +// delegators - a map from address to its share (< 100) +// shareRewardsCallback - a callback to send `coins` of total rewards to `addr` +func SplitNodeRewards( + logger log.Logger, + rewards sdk.BigInt, + primaryRecipient sdk.Address, + delegators map[string]uint32, + shareRewardsCallback func(addr sdk.Address, coins sdk.BigInt), +) error { + if !rewards.IsPositive() { + return errors.New("non-positive rewards") + } + + normalizedDelegators, err := types.NormalizeRewardDelegators(delegators) + if err != nil { + // If the delegators field is invalid, do nothing. + return errors.New("invalid delegators") + } + + remains := rewards + for _, pair := range normalizedDelegators { + percentage := sdk.NewDecWithPrec(int64(pair.RewardShare), 2) + allocation := rewards.ToDec().Mul(percentage).TruncateInt() + if allocation.IsPositive() { + shareRewardsCallback(pair.Address, allocation) + } + remains = remains.Sub(allocation) + } + + if remains.IsPositive() { + shareRewardsCallback(primaryRecipient, remains) + } else { + delegatorsBytes, _ := json.Marshal(delegators) + logger.Error( + "over-distributed rewards to delegators", + "rewards", rewards, + "remains", remains, + "delegators", string(delegatorsBytes), + ) + } + return nil +} + // Calculates a chain-specific Relays-To-Token-Multiplier. // Returns the default multiplier if the feature is not activated or a given // chain is not set in the parameter. @@ -97,38 +227,70 @@ func (k Keeper) GetChainSpecificMultiplier(ctx sdk.Ctx, chain string) sdk.BigInt func (k Keeper) blockReward(ctx sdk.Ctx, previousProposer sdk.Address) { feesCollector := k.getFeePool(ctx) feesCollected := feesCollector.GetCoins().AmountOf(sdk.DefaultStakeDenom) - // check for zero fees if feesCollected.IsZero() { return } - // get the dao and proposer % ex DAO .1 or 10% Proposer .01 or 1% - daoAllocation := sdk.NewDec(k.DAOAllocation(ctx)) - proposerAllocation := sdk.NewDec(k.ProposerAllocation(ctx)) - daoAndProposerAllocation := daoAllocation.Add(proposerAllocation) - // get the new percentages based on the total. This is needed because the node (relayer) cut has already been allocated - daoAllocation = daoAllocation.Quo(daoAndProposerAllocation) - // dao cut calculation truncates int ex: 1.99uPOKT = 1uPOKT - daoCut := feesCollected.ToDec().Mul(daoAllocation).TruncateInt() - // proposer is whatever is left - proposerCut := feesCollected.Sub(daoCut) + + daoCut, proposerCut := k.splitFeesCollected(ctx, feesCollected) + // send to the two parties feeAddr := feesCollector.GetAddress() err := k.AccountKeeper.SendCoinsFromAccountToModule(ctx, feeAddr, govTypes.DAOAccountName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultStakeDenom, daoCut))) if err != nil { - ctx.Logger().Error(fmt.Sprintf("unable to send %s cut of block reward to the dao: %s, at height %d", daoCut.String(), err.Error(), ctx.BlockHeight())) + ctx.Logger().Error("unable to send a DAO cut of block reward", + "height", ctx.BlockHeight(), + "cut", daoCut, + "err", err.Error(), + ) } + if k.Cdc.IsAfterNonCustodialUpgrade(ctx.BlockHeight()) { - outputAddress, found := k.GetValidatorOutputAddress(ctx, previousProposer) + validator, found := k.GetValidator(ctx, previousProposer) if !found { - ctx.Logger().Error(fmt.Sprintf("unable to send %s cut of block reward to the proposer: %s, with error %s, at height %d", proposerCut.String(), previousProposer, types.ErrNoValidatorForAddress(types.ModuleName), ctx.BlockHeight())) + ctx.Logger().Error("unable to find a validator to send a block reward to", + "height", ctx.BlockHeight(), + "addr", previousProposer, + ) return } - err = k.AccountKeeper.SendCoins(ctx, feeAddr, outputAddress, sdk.NewCoins(sdk.NewCoin(sdk.DefaultStakeDenom, proposerCut))) + + if !k.Cdc.IsAfterRewardDelegatorUpgrade(ctx.BlockHeight()) { + validator.RewardDelegators = nil + } + + err := SplitNodeRewards( + ctx.Logger(), + proposerCut, + k.GetOutputAddressFromValidator(validator), + validator.RewardDelegators, + func(recipient sdk.Address, share sdk.BigInt) { + err = k.AccountKeeper.SendCoins( + ctx, + feeAddr, + recipient, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultStakeDenom, share)), + ) + if err != nil { + ctx.Logger().Error("unable to send a cut of block reward", + "height", ctx.BlockHeight(), + "cut", share, + "addr", recipient, + "err", err.Error(), + ) + } + }, + ) if err != nil { - ctx.Logger().Error(fmt.Sprintf("unable to send %s cut of block reward to the proposer: %s, with error %s, at height %d", proposerCut.String(), previousProposer, err.Error(), ctx.BlockHeight())) + ctx.Logger().Error("unable to split block rewards", + "height", ctx.BlockHeight(), + "validator", validator.Address, + "err", err.Error(), + ) } + return } + err = k.AccountKeeper.SendCoins(ctx, feeAddr, previousProposer, sdk.NewCoins(sdk.NewCoin(sdk.DefaultStakeDenom, proposerCut))) if err != nil { ctx.Logger().Error(fmt.Sprintf("unable to send %s cut of block reward to the proposer: %s, with error %s, at height %d", proposerCut.String(), previousProposer, err.Error(), ctx.BlockHeight())) diff --git a/x/nodes/keeper/reward_test.go b/x/nodes/keeper/reward_test.go index 078a6727c..509bb1717 100644 --- a/x/nodes/keeper/reward_test.go +++ b/x/nodes/keeper/reward_test.go @@ -1,12 +1,15 @@ package keeper import ( + "encoding/binary" + "fmt" "testing" "github.com/pokt-network/pocket-core/codec" sdk "github.com/pokt-network/pocket-core/types" "github.com/pokt-network/pocket-core/x/nodes/types" "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/libs/log" ) type args struct { @@ -87,6 +90,27 @@ func TestMint(t *testing.T) { } } +func verifyAccountBalance( + t *testing.T, + k Keeper, + ctx sdk.Context, + address sdk.Address, + expected sdk.BigInt, +) { + acc := k.GetAccount(ctx, address) + expectedCoins := sdk.NewCoins(sdk.NewCoin("upokt", expected)) + assert.True( + t, + acc.Coins.IsEqual(expectedCoins), + fmt.Sprintf( + "Balance mismatch in %v, actual=%v expected=%v", + address, + acc.Coins, + expectedCoins, + ), + ) +} + func TestKeeper_rewardFromFees(t *testing.T) { type fields struct { keeper Keeper @@ -117,6 +141,13 @@ func TestKeeper_rewardFromFees(t *testing.T) { fp = keeper.getFeePool(context) keeper.SetValidator(context, stakedValidator) assert.Equal(t, fees, fp.GetCoins()) + + _, proposerCut := keeper.splitFeesCollected(context, amount) + + totalSupplyPrev := keeper.AccountKeeper.GetSupply(context). + GetTotal(). + AmountOf("upokt") + tests := []struct { name string fields fields @@ -134,11 +165,14 @@ func TestKeeper_rewardFromFees(t *testing.T) { k := tt.fields.keeper ctx := tt.args.ctx k.blockReward(tt.args.ctx, tt.args.previousProposer) - acc := k.GetAccount(ctx, tt.args.Output) - assert.False(t, acc.Coins.IsZero()) - assert.True(t, acc.Coins.IsEqual(sdk.NewCoins(sdk.NewCoin("upokt", sdk.NewInt(910))))) - acc = k.GetAccount(ctx, tt.args.previousProposer) - assert.True(t, acc.Coins.IsZero()) + + verifyAccountBalance(t, k, ctx, tt.args.Output, proposerCut) + verifyAccountBalance(t, k, ctx, tt.args.previousProposer, sdk.ZeroInt()) + + totalSupply := k.AccountKeeper.GetSupply(ctx). + GetTotal(). + AmountOf("upokt") + assert.True(t, totalSupply.Equal(totalSupplyPrev)) }) } } @@ -183,26 +217,41 @@ func TestKeeper_rewardFromRelays(t *testing.T) { validator: stakedValidator.GetAddress(), Output: stakedValidator.OutputAddress, validatorNoOutput: stakedValidatorNoOutput.GetAddress(), - OutputNoOutput: stakedValidatorNoOutput.GetAddress(), }}, } + + totalSupplyPrev := keeper.AccountKeeper.GetSupply(context). + GetTotal(). + AmountOf("upokt") + + relays := sdk.NewInt(10000) + rewardCost := keeper.GetRewardCost(context) + totalReward := relays.Mul(keeper.RelaysToTokensMultiplier(context)) + nodeReward, _ := keeper.splitRewards(context, totalReward) + outputReward := nodeReward.Sub(rewardCost) + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { k := tt.fields.keeper ctx := tt.args.ctx - k.RewardForRelays(tt.args.ctx, sdk.NewInt(10000), tt.args.validator) - acc := k.GetAccount(ctx, tt.args.Output) - assert.False(t, acc.Coins.IsZero()) - assert.True(t, acc.Coins.IsEqual(sdk.NewCoins(sdk.NewCoin("upokt", sdk.NewInt(8900000))))) - acc = k.GetAccount(ctx, tt.args.validator) - assert.True(t, acc.Coins.IsZero()) + + k.RewardForRelays(tt.args.ctx, relays, tt.args.validator) + verifyAccountBalance(t, k, ctx, tt.args.Output, outputReward) + verifyAccountBalance(t, k, ctx, tt.args.validator, rewardCost) + + totalSupply := k.AccountKeeper.GetSupply(ctx). + GetTotal(). + AmountOf("upokt") + assert.True(t, totalSupply.Equal(totalSupplyPrev.Add(totalReward))) + // no output now - k.RewardForRelays(tt.args.ctx, sdk.NewInt(10000), tt.args.validatorNoOutput) - acc = k.GetAccount(ctx, tt.args.OutputNoOutput) - assert.False(t, acc.Coins.IsZero()) - assert.True(t, acc.Coins.IsEqual(sdk.NewCoins(sdk.NewCoin("upokt", sdk.NewInt(8900000))))) - acc2 := k.GetAccount(ctx, tt.args.validatorNoOutput) - assert.Equal(t, acc, acc2) + k.RewardForRelays(tt.args.ctx, relays, tt.args.validatorNoOutput) + verifyAccountBalance(t, k, ctx, tt.args.validatorNoOutput, nodeReward) + + totalSupply = k.AccountKeeper.GetSupply(ctx). + GetTotal(). + AmountOf("upokt") + assert.True(t, totalSupply.Equal(totalSupplyPrev.Add(totalReward.MulRaw(2)))) }) } } @@ -426,6 +475,7 @@ func TestKeeper_rewardFromRelaysPIP22EXP(t *testing.T) { func TestKeeper_RewardForRelaysPerChain(t *testing.T) { Height_PIP22 := int64(3) Height_PerChainRTTM := int64(10) + Height_Delegator := int64(10) Chain_Normal := "0001" Chain_HighProfit := "0002" RTTM_Default := int64(10000) @@ -443,6 +493,10 @@ func TestKeeper_RewardForRelaysPerChain(t *testing.T) { QuoRaw(100) } + originalFeatureMap := codec.UpgradeFeatureMap + t.Cleanup(func() { + codec.UpgradeFeatureMap = originalFeatureMap + }) codec.UpgradeFeatureMap[codec.RSCALKey] = Height_PIP22 codec.UpgradeFeatureMap[codec.PerChainRTTM] = Height_PerChainRTTM @@ -506,6 +560,164 @@ func TestKeeper_RewardForRelaysPerChain(t *testing.T) { NumOfRelays, validator.Address, ) - assert.True(t, rewardsHighProfit.Equal(ExpectedRewards(RTTM_High))) + expectedRewardsHighProfit := ExpectedRewards(RTTM_High) + assert.True(t, rewardsHighProfit.Equal(expectedRewardsHighProfit)) assert.True(t, rewardsDefault.LT(rewardsHighProfit)) + + // After the RewardDelegators upgrade, a servicer is compensated for + // the reward cost (= transactions fees). Therefore the expected rewards + // is decreased by the reward cost. + codec.UpgradeFeatureMap[codec.RewardDelegatorsKey] = Height_Delegator + rewardCost := keeper.GetRewardCost(ctx) + expectedRewardsHighProfit = expectedRewardsHighProfit.Sub(rewardCost) + rewardsHighProfit = keeper.RewardForRelaysPerChain( + ctx, + Chain_HighProfit, + NumOfRelays, + validator.Address, + ) + assert.True(t, rewardsHighProfit.Equal(expectedRewardsHighProfit)) +} + +func toArray(addr sdk.Address) [sdk.AddrLen]byte { + var arr [sdk.AddrLen]byte + copy(arr[:], addr) + return arr +} + +func indexToAddress(index int) sdk.Address { + addr := make([]byte, sdk.AddrLen) + binary.BigEndian.PutUint64(addr, uint64(index)) + return addr +} + +func TestKeeper_SplitNodeRewards(t *testing.T) { + var result map[[sdk.AddrLen]byte]sdk.BigInt + callback := func(addr sdk.Address, rewards sdk.BigInt) { + result[toArray(addr)] = rewards + } + logger := log.NewNopLogger() + recipient, _ := sdk.AddressFromHex("ffffffffffffffffffffffffffffffffffffffff") + + verifyResult := func( + t *testing.T, + totalRewards sdk.BigInt, + expectedBalances []uint64, + ) { + // Verify each delegator receives expected rewards + for idx, expectedBalance := range expectedBalances { + rewardsResult, found := result[toArray(indexToAddress(idx))] + if expectedBalance == 0 { + assert.False(t, found, "Rewards shouldn't be dispatched") + continue + } + assert.True(t, found, "Rewards not dispatched") + if !found { + continue + } + assert.Equal(t, expectedBalance, rewardsResult.Uint64(), "Wrong rewards") + totalRewards = totalRewards.Sub(rewardsResult) + } + + assert.False(t, totalRewards.IsNegative(), "Too many rewards") + + // Verify the recipient receives the remains if any exists + reward, found := result[toArray(recipient)] + if totalRewards.IsZero() { + assert.False(t, found) + return + } + assert.True(t, found) + if !found { + return + } + assert.True(t, reward.Equal(totalRewards)) + } + + delegatorMap := func(shares []uint32) map[string]uint32 { + if len(shares) == 0 { + return nil + } + m := map[string]uint32{} + for idx, share := range shares { + m[indexToAddress(idx).String()] = share + } + return m + } + + totalBig := sdk.NewInt(10004) + totalSmall := sdk.NewInt(81) + + // All goes to the default recipient. + result = map[[sdk.AddrLen]byte]sdk.BigInt{} + SplitNodeRewards( + logger, + totalBig, + recipient, + delegatorMap([]uint32{}), + callback, + ) + verifyResult(t, totalBig, []uint64{}) + + // All goes to the delegator. + result = map[[sdk.AddrLen]byte]sdk.BigInt{} + SplitNodeRewards( + logger, + totalBig, + recipient, + delegatorMap([]uint32{100}), + callback, + ) + verifyResult(t, totalBig, []uint64{totalBig.Uint64()}) + + // Multiple delegators. Remainder goes to the recipient. + result = map[[sdk.AddrLen]byte]sdk.BigInt{} + SplitNodeRewards( + logger, + totalBig, + recipient, + delegatorMap([]uint32{1, 2, 30, 50}), + callback, + ) + verifyResult(t, totalBig, []uint64{100, 200, 3001, 5002}) + + // Share less than a single token is truncated. + result = map[[sdk.AddrLen]byte]sdk.BigInt{} + SplitNodeRewards( + logger, + totalSmall, + recipient, + delegatorMap([]uint32{1, 1, 1, 1}), + callback, + ) + verifyResult(t, totalSmall, []uint64{}) + result = map[[sdk.AddrLen]byte]sdk.BigInt{} + SplitNodeRewards( + logger, + totalSmall, + recipient, + delegatorMap([]uint32{1, 2}), + callback, + ) + verifyResult(t, totalSmall, []uint64{0, 1}) + + // Invalid delegator map: nothing happens + result = map[[sdk.AddrLen]byte]sdk.BigInt{} + SplitNodeRewards( + logger, + totalSmall, + recipient, + delegatorMap([]uint32{1, 0xffffffff}), // exceeds 100, no overflow + callback, + ) + assert.Zero(t, len(result)) + result = map[[sdk.AddrLen]byte]sdk.BigInt{} + SplitNodeRewards( + logger, + totalSmall, + recipient, + delegatorMap([]uint32{1, 2, 0}), // zero share + callback, + ) + assert.Zero(t, len(result)) } diff --git a/x/nodes/keeper/valStateChanges.go b/x/nodes/keeper/valStateChanges.go index d559b6f86..ac33b42bb 100644 --- a/x/nodes/keeper/valStateChanges.go +++ b/x/nodes/keeper/valStateChanges.go @@ -261,6 +261,21 @@ func (k Keeper) ValidateEditStake(ctx sdk.Ctx, currentValidator, newValidtor typ return types.ErrUnequalOutputAddr(k.Codespace()) } } + + // Following PIP-32, RewardDelegators can be set/edited only if: + // 1) The feature has been activated AND + // 2) the message is signed by the operator address. + // For more details, see + // https://forum.pokt.network/t/pip32-unleashing-the-potential-of-non-custodial-node-running/4796 + if k.Cdc.IsAfterRewardDelegatorUpgrade(ctx.BlockHeight()) && + !types.CompareStringMaps( + currentValidator.RewardDelegators, + newValidtor.RewardDelegators, + ) && + !signer.Equals(currentValidator.Address) { + return types.ErrDisallowedRewardDelegatorEdit(k.Codespace()) + } + // prevent waiting vals from modifying anything if k.IsWaitingValidator(ctx, currentValidator.Address) { return types.ErrValidatorWaitingToUnstake(types.ModuleName) @@ -328,6 +343,11 @@ func (k Keeper) EditStakeValidator(ctx sdk.Ctx, currentValidator, updatedValidat currentValidator.OutputAddress == nil { currentValidator.OutputAddress = updatedValidator.OutputAddress } + + // After the upgrade, we allow delegators change + if k.Cdc.IsAfterRewardDelegatorUpgrade(ctx.BlockHeight()) { + currentValidator.RewardDelegators = updatedValidator.RewardDelegators + } } // update chains currentValidator.Chains = updatedValidator.Chains diff --git a/x/nodes/keeper/valStateChanges_test.go b/x/nodes/keeper/valStateChanges_test.go index cff7c1155..a476ac9d3 100644 --- a/x/nodes/keeper/valStateChanges_test.go +++ b/x/nodes/keeper/valStateChanges_test.go @@ -369,13 +369,8 @@ func handleStakeForTesting( msg types.MsgStake, signer crypto.PublicKey, ) sdk.Error { - validator := types.NewValidator( - sdk.Address(msg.PublicKey.Address()), - msg.PublicKey, - msg.Chains, - msg.ServiceUrl, - sdk.ZeroInt(), - msg.Output) + validator := types.NewValidatorFromMsg(msg) + validator.StakedTokens = sdk.ZeroInt() if err := k.ValidateValidatorStaking( ctx, validator, msg.Value, sdk.Address(signer.Address())); err != nil { return err @@ -498,6 +493,103 @@ func TestValidatorStateChange_OutputAddressEdit(t *testing.T) { assert.Equal(t, validatorCur.OutputAddress, outputAddress) } +func TestValidatorStateChange_Delegators(t *testing.T) { + ctx, _, k := createTestInput(t, true) + + originalUpgradeHeight := codec.UpgradeHeight + originalTestMode := codec.TestMode + originalNCUST := codec.UpgradeFeatureMap[codec.NonCustodialUpdateKey] + originalOEDIT := codec.UpgradeFeatureMap[codec.OutputAddressEditKey] + originalReward := codec.UpgradeFeatureMap[codec.RewardDelegatorsKey] + t.Cleanup(func() { + codec.UpgradeHeight = originalUpgradeHeight + codec.TestMode = originalTestMode + codec.UpgradeFeatureMap[codec.NonCustodialUpdateKey] = originalNCUST + codec.UpgradeFeatureMap[codec.OutputAddressEditKey] = originalOEDIT + codec.UpgradeFeatureMap[codec.RewardDelegatorsKey] = originalReward + }) + + // Enable EditStake, NCUST, and OEDIT + codec.TestMode = 0 + codec.UpgradeHeight = -1 + codec.UpgradeFeatureMap[codec.NonCustodialUpdateKey] = -1 + codec.UpgradeFeatureMap[codec.OutputAddressEditKey] = -1 + + // Prepare accounts + outputPubKey := getRandomPubKey() + operatorPubKey1 := getRandomPubKey() + operatorPubKey2 := getRandomPubKey() + operatorAddr1 := sdk.Address(operatorPubKey1.Address()) + outputAddress := sdk.Address(outputPubKey.Address()) + operatorAddr2 := sdk.Address(operatorPubKey2.Address()) + + // Fund output address for two nodes + stakeAmount := sdk.NewCoin(k.StakeDenom(ctx), sdk.NewInt(k.MinimumStake(ctx))) + assert.Nil(t, fundAccount(ctx, k, outputAddress, stakeAmount)) + assert.Nil(t, fundAccount(ctx, k, outputAddress, stakeAmount)) + + runStake := func( + operatorPubkey crypto.PublicKey, + delegators map[string]uint32, + signer crypto.PublicKey, + ) sdk.Error { + msgStake := types.MsgStake{ + Chains: []string{"0021", "0040"}, + ServiceUrl: "https://www.pokt.network:443", + Value: stakeAmount.Amount, + PublicKey: operatorPubkey, + Output: outputAddress, + RewardDelegators: delegators, + } + return handleStakeForTesting(ctx, k, msgStake, signer) + } + + singleDelegator := map[string]uint32{} + singleDelegator[getRandomValidatorAddress().String()] = 1 + + // Attempt to set a delegators before the upgrade --> The field is ignored + assert.Nil(t, runStake(operatorPubKey1, singleDelegator, outputPubKey)) + validatorCur, found := k.GetValidator(ctx, operatorAddr1) + assert.True(t, found) + assert.Nil(t, validatorCur.RewardDelegators) + + // Enable RewardDelegators + codec.UpgradeFeatureMap[codec.RewardDelegatorsKey] = -1 + + // Attempt to change the delegators with output's signature --> Fail + err := runStake(operatorPubKey1, singleDelegator, outputPubKey) + assert.NotNil(t, err) + assert.Equal(t, k.codespace, err.Codespace()) + assert.Equal(t, types.CodeDisallowedRewardDelegatorEdit, err.Code()) + + // Attempt to set the delegators with operator's signature --> Success + err = runStake(operatorPubKey1, singleDelegator, operatorPubKey1) + assert.Nil(t, err) + validatorCur, found = k.GetValidator(ctx, operatorAddr1) + assert.True(t, found) + assert.True( + t, + types.CompareStringMaps(validatorCur.RewardDelegators, singleDelegator), + ) + + // Attempt to reset the delegators with operator's signature --> Success + err = runStake(operatorPubKey1, nil, operatorPubKey1) + assert.Nil(t, err) + validatorCur, found = k.GetValidator(ctx, operatorAddr1) + assert.True(t, found) + assert.Nil(t, validatorCur.RewardDelegators) + + // New stake with delegators can be signed by the output --> Success + err = runStake(operatorPubKey2, singleDelegator, outputPubKey) + assert.Nil(t, err) + validatorCur, found = k.GetValidator(ctx, operatorAddr2) + assert.True(t, found) + assert.True( + t, + types.CompareStringMaps(validatorCur.RewardDelegators, singleDelegator), + ) +} + func TestKeeper_JailValidator(t *testing.T) { type fields struct { keeper Keeper diff --git a/x/nodes/keeper/validator.go b/x/nodes/keeper/validator.go index c0163feeb..92161cebd 100644 --- a/x/nodes/keeper/validator.go +++ b/x/nodes/keeper/validator.go @@ -11,6 +11,9 @@ import ( func (k Keeper) MarshalValidator(ctx sdk.Ctx, validator types.Validator) ([]byte, error) { if k.Cdc.IsAfterNonCustodialUpgrade(ctx.BlockHeight()) { + if !k.Cdc.IsAfterRewardDelegatorUpgrade(ctx.BlockHeight()) { + validator.RewardDelegators = nil + } bz, err := k.Cdc.MarshalBinaryLengthPrefixed(&validator, ctx.BlockHeight()) if err != nil { ctx.Logger().Error("could not marshal validator: " + err.Error()) @@ -28,7 +31,11 @@ func (k Keeper) MarshalValidator(ctx sdk.Ctx, validator types.Validator) ([]byte func (k Keeper) UnmarshalValidator(ctx sdk.Ctx, valBytes []byte) (val types.Validator, err error) { if k.Cdc.IsAfterNonCustodialUpgrade(ctx.BlockHeight()) { err = k.Cdc.UnmarshalBinaryLengthPrefixed(valBytes, &val, ctx.BlockHeight()) - if err != nil { + if err == nil { + if !k.Cdc.IsAfterRewardDelegatorUpgrade(ctx.BlockHeight()) { + val.RewardDelegators = nil + } + } else { ctx.Logger().Error("could not unmarshal validator: " + err.Error()) } return val, err diff --git a/x/nodes/keeper/validator_test.go b/x/nodes/keeper/validator_test.go index a66589d91..befbb420d 100644 --- a/x/nodes/keeper/validator_test.go +++ b/x/nodes/keeper/validator_test.go @@ -2,11 +2,12 @@ package keeper import ( "fmt" + "reflect" + "testing" + sdk "github.com/pokt-network/pocket-core/types" "github.com/pokt-network/pocket-core/x/nodes/types" "github.com/stretchr/testify/assert" - "reflect" - "testing" ) func TestKeeper_GetValidators(t *testing.T) { @@ -148,3 +149,70 @@ func Test_sortNoLongerStakedValidators(t *testing.T) { }) } } + +// There are two versions of structs to represent a validator. +// - LegacyValidator - the original version +// - Validator - LegacyValidator + OutputAddress + Delegators (since 0.11) +// +// The following test verifies marshaling/unmarshaling has backward/forward +// compatibility, meaning marshaled bytes can be unmarshaled as a newer version +// or an older version. +// +// We cover the Proto marshaler only because Amino marshaler does not support +// a map type used in handle type.Validator. +// We used Amino before UpgradeCodecHeight and we no longer use it, so it's +// ok not to cover Amino. +func TestValidator_Proto_MarshalingCompatibility(t *testing.T) { + _, _, k := createTestInput(t, false) + Marshal := k.Cdc.ProtoCodec().MarshalBinaryLengthPrefixed + Unmarshal := k.Cdc.ProtoCodec().UnmarshalBinaryLengthPrefixed + + var ( + val_1, val_2 types.Validator + valL_1, valL_2 types.LegacyValidator + marshaled []byte + err error + ) + + val_1 = getStakedValidator() + val_1.OutputAddress = getRandomValidatorAddress() + val_1.RewardDelegators = map[string]uint32{} + val_1.RewardDelegators[getRandomValidatorAddress().String()] = 10 + val_1.RewardDelegators[getRandomValidatorAddress().String()] = 20 + valL_1 = val_1.ToLegacy() + + // Validator --> []byte --> Validator + marshaled, err = Marshal(&val_1) + assert.Nil(t, err) + assert.NotNil(t, marshaled) + val_2.Reset() + err = Unmarshal(marshaled, &val_2) + assert.Nil(t, err) + assert.True(t, val_2.ToLegacy().Equals(val_1.ToLegacy())) + assert.True(t, val_2.OutputAddress.Equals(val_1.OutputAddress)) + assert.NotNil(t, val_2.RewardDelegators) + assert.True( + t, + types.CompareStringMaps(val_2.RewardDelegators, val_1.RewardDelegators), + ) + + // Validator --> []byte --> LegacyValidator + marshaled, err = Marshal(&val_1) + assert.Nil(t, err) + assert.NotNil(t, marshaled) + valL_2.Reset() + err = Unmarshal(marshaled, &valL_2) + assert.Nil(t, err) + assert.True(t, valL_2.Equals(val_1.ToLegacy())) + + // LegacyValidator --> []byte --> Validator + marshaled, err = Marshal(&valL_1) + assert.Nil(t, err) + assert.NotNil(t, marshaled) + val_2.Reset() + err = Unmarshal(marshaled, &val_2) + assert.Nil(t, err) + assert.True(t, val_2.ToLegacy().Equals(valL_1)) + assert.Nil(t, val_2.OutputAddress) + assert.Nil(t, val_2.RewardDelegators) +} diff --git a/x/nodes/types/errors.go b/x/nodes/types/errors.go index 49a771ebd..ebc1c44e7 100644 --- a/x/nodes/types/errors.go +++ b/x/nodes/types/errors.go @@ -10,33 +10,35 @@ import ( type CodeType = sdk.CodeType const ( - DefaultCodespace sdk.CodespaceType = ModuleName - CodeInvalidValidator CodeType = 101 - CodeInvalidDelegation CodeType = 102 - CodeInvalidInput CodeType = 103 - CodeValidatorJailed CodeType = 104 - CodeValidatorNotJailed CodeType = 105 - CodeMissingSelfDelegation CodeType = 106 - CodeMissingSigningInfo CodeType = 108 - CodeBadSend CodeType = 109 - CodeInvalidStatus CodeType = 110 - CodeMinimumStake CodeType = 111 - CodeNotEnoughCoins CodeType = 112 - CodeValidatorTombstoned CodeType = 113 - CodeCantHandleEvidence CodeType = 114 - CodeNoChains CodeType = 115 - CodeNoServiceURL CodeType = 116 - CodeWaitingValidator CodeType = 117 - CodeInvalidServiceURL CodeType = 118 - CodeInvalidNetworkIdentifier CodeType = 119 - CodeTooManyChains CodeType = 120 - CodeStateConvertError CodeType = 121 - CodeMinimumEditStake CodeType = 122 - CodeNilOutputAddr CodeType = 123 - CodeUnequalOutputAddr CodeType = 124 - CodeUnauthorizedSigner CodeType = 125 - CodeNilSigner CodeType = 126 - CodeDisallowedOutputAddressEdit CodeType = 127 + DefaultCodespace sdk.CodespaceType = ModuleName + CodeInvalidValidator CodeType = 101 + CodeInvalidDelegation CodeType = 102 + CodeInvalidInput CodeType = 103 + CodeValidatorJailed CodeType = 104 + CodeValidatorNotJailed CodeType = 105 + CodeMissingSelfDelegation CodeType = 106 + CodeMissingSigningInfo CodeType = 108 + CodeBadSend CodeType = 109 + CodeInvalidStatus CodeType = 110 + CodeMinimumStake CodeType = 111 + CodeNotEnoughCoins CodeType = 112 + CodeValidatorTombstoned CodeType = 113 + CodeCantHandleEvidence CodeType = 114 + CodeNoChains CodeType = 115 + CodeNoServiceURL CodeType = 116 + CodeWaitingValidator CodeType = 117 + CodeInvalidServiceURL CodeType = 118 + CodeInvalidNetworkIdentifier CodeType = 119 + CodeTooManyChains CodeType = 120 + CodeStateConvertError CodeType = 121 + CodeMinimumEditStake CodeType = 122 + CodeNilOutputAddr CodeType = 123 + CodeUnequalOutputAddr CodeType = 124 + CodeUnauthorizedSigner CodeType = 125 + CodeNilSigner CodeType = 126 + CodeDisallowedOutputAddressEdit CodeType = 127 + CodeInvalidRewardDelegators CodeType = 128 + CodeDisallowedRewardDelegatorEdit CodeType = 129 ) func ErrTooManyChains(codespace sdk.CodespaceType) sdk.Error { @@ -160,3 +162,13 @@ func ErrDisallowedOutputAddressEdit(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeDisallowedOutputAddressEdit, "Only the owner of the current output address can edit the output address") } + +func ErrInvalidRewardDelegators(codespace sdk.CodespaceType, reason string) sdk.Error { + return sdk.NewError(codespace, CodeInvalidRewardDelegators, + "Invalid reward delegators: %s", reason) +} + +func ErrDisallowedRewardDelegatorEdit(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeDisallowedRewardDelegatorEdit, + "Only the node operator address can edit reward delegators") +} diff --git a/x/nodes/types/expectedKeepers.go b/x/nodes/types/expectedKeepers.go index dcec40405..f8fac38bb 100644 --- a/x/nodes/types/expectedKeepers.go +++ b/x/nodes/types/expectedKeepers.go @@ -8,38 +8,23 @@ import ( // AuthKeeper defines the expected supply Keeper (noalias) type AuthKeeper interface { - // get total supply of tokens GetSupply(ctx sdk.Ctx) authexported.SupplyI - // set total supply of tokens SetSupply(ctx sdk.Ctx, supply authexported.SupplyI) - // get the address of a module account GetModuleAddress(name string) sdk.Address - // get the module account structure GetModuleAccount(ctx sdk.Ctx, moduleName string) authexported.ModuleAccountI - // set module account structure SetModuleAccount(sdk.Ctx, authexported.ModuleAccountI) - // send coins to/from module accounts SendCoinsFromModuleToModule(ctx sdk.Ctx, senderModule, recipientModule string, amt sdk.Coins) sdk.Error - // send coins from module to validator SendCoinsFromModuleToAccount(ctx sdk.Ctx, senderModule string, recipientAddr sdk.Address, amt sdk.Coins) sdk.Error - // send coins from validator to module SendCoinsFromAccountToModule(ctx sdk.Ctx, senderAddr sdk.Address, recipientModule string, amt sdk.Coins) sdk.Error - // mint coins MintCoins(ctx sdk.Ctx, moduleName string, amt sdk.Coins) sdk.Error - // burn coins BurnCoins(ctx sdk.Ctx, name string, amt sdk.Coins) sdk.Error - // iterate accounts IterateAccounts(ctx sdk.Ctx, process func(authexported.Account) (stop bool)) - // get coins GetCoins(ctx sdk.Ctx, addr sdk.Address) sdk.Coins - // set coins SetCoins(ctx sdk.Ctx, addr sdk.Address, amt sdk.Coins) sdk.Error - // has coins HasCoins(ctx sdk.Ctx, addr sdk.Address, amt sdk.Coins) bool - // send coins SendCoins(ctx sdk.Ctx, fromAddr sdk.Address, toAddr sdk.Address, amt sdk.Coins) sdk.Error - // get account GetAccount(ctx sdk.Ctx, addr sdk.Address) authexported.Account + GetFee(ctx sdk.Ctx, msg sdk.Msg) sdk.BigInt } type PocketKeeper interface { diff --git a/x/nodes/types/msg.go b/x/nodes/types/msg.go index 3f8ca88ff..fbc23d13c 100644 --- a/x/nodes/types/msg.go +++ b/x/nodes/types/msg.go @@ -1,7 +1,9 @@ package types import ( + "encoding/json" "fmt" + "github.com/pokt-network/pocket-core/codec" "github.com/pokt-network/pocket-core/crypto" sdk "github.com/pokt-network/pocket-core/types" @@ -22,7 +24,7 @@ const ( MsgSendName = "send" ) -//---------------------------------------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------------------------------------- // GetSigners return address(es) that must sign over msg.GetSignBytes() func (msg MsgBeginUnstake) GetSigners() []sdk.Address { return []sdk.Address{msg.Signer, msg.Address} @@ -141,16 +143,17 @@ func (msg MsgSend) GetFee() sdk.BigInt { return sdk.NewInt(NodeFeeMap[msg.Type()]) } -//---------------------------------------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------------------------------------- var _ codec.ProtoMarshaler = &MsgStake{} // MsgStake - struct for staking transactions type MsgStake struct { - PublicKey crypto.PublicKey `json:"public_key" yaml:"public_key"` - Chains []string `json:"chains" yaml:"chains"` - Value sdk.BigInt `json:"value" yaml:"value"` - ServiceUrl string `json:"service_url" yaml:"service_url"` - Output sdk.Address `json:"output_address,omitempty" yaml:"output_address"` + PublicKey crypto.PublicKey `json:"public_key" yaml:"public_key"` + Chains []string `json:"chains" yaml:"chains"` + Value sdk.BigInt `json:"value" yaml:"value"` + ServiceUrl string `json:"service_url" yaml:"service_url"` + Output sdk.Address `json:"output_address,omitempty" yaml:"output_address"` + RewardDelegators map[string]uint32 `json:"reward_delegators,omitempty" yaml:"reward_delegators"` } func (msg *MsgStake) Marshal() ([]byte, error) { @@ -184,11 +187,12 @@ func (msg *MsgStake) Unmarshal(data []byte) error { return err } newMsg := MsgStake{ - PublicKey: publicKey, - Chains: m.Chains, - Value: m.Value, - ServiceUrl: m.ServiceUrl, - Output: m.OutputAddress, + PublicKey: publicKey, + Chains: m.Chains, + Value: m.Value, + ServiceUrl: m.ServiceUrl, + Output: m.OutputAddress, + RewardDelegators: m.RewardDelegators, } *msg = newMsg return nil @@ -229,6 +233,11 @@ func (msg MsgStake) ValidateBasic() sdk.Error { if err := ValidateServiceURL(msg.ServiceUrl); err != nil { return err } + if msg.RewardDelegators != nil { + if err := msg.CheckRewardDelegators(); err != nil { + return err + } + } return nil } @@ -252,7 +261,26 @@ func (msg *MsgStake) XXX_MessageName() string { } func (msg MsgStake) String() string { - return fmt.Sprintf("Public Key: %s\nChains: %s\nValue: %s\nOutputAddress: %s\n", msg.PublicKey.RawString(), msg.Chains, msg.Value.String(), msg.Output) + delegatorsStr := "" + if msg.RewardDelegators != nil { + if jsonBytes, err := json.Marshal(msg.RewardDelegators); err == nil { + delegatorsStr = string(jsonBytes) + } else { + delegatorsStr = err.Error() + } + } + return fmt.Sprintf(`Public Key: %s +Chains: %s +Value: %s +OutputAddress: %s +RewardDelegators: %s +`, + msg.PublicKey.RawString(), + msg.Chains, + msg.Value.String(), + msg.Output, + delegatorsStr, + ) } func (msg *MsgStake) ProtoMessage() { @@ -268,11 +296,12 @@ func (msg MsgStake) ToProto() MsgProtoStake { pubKeyBz = msg.PublicKey.RawBytes() } return MsgProtoStake{ - Publickey: pubKeyBz, - Chains: msg.Chains, - Value: msg.Value, - ServiceUrl: msg.ServiceUrl, - OutputAddress: msg.Output, + Publickey: pubKeyBz, + Chains: msg.Chains, + Value: msg.Value, + ServiceUrl: msg.ServiceUrl, + OutputAddress: msg.Output, + RewardDelegators: msg.RewardDelegators, } } @@ -283,6 +312,52 @@ func (msg MsgStake) CheckServiceUrlLength(url string) sdk.Error { return nil } +func (msg MsgStake) CheckRewardDelegators() sdk.Error { + _, err := NormalizeRewardDelegators(msg.RewardDelegators) + return err +} + +type AddressAndShare struct { + Address sdk.Address + RewardShare uint32 // always positive +} + +// NormalizeRewardDelegators returns an slice of delegator addresses and +// their shares if the map is valid. +func NormalizeRewardDelegators( + delegators map[string]uint32, +) ([]AddressAndShare, sdk.Error) { + normalized := make([]AddressAndShare, 0, len(delegators)) + totalShares := uint64(0) + for addrStr, rewardShare := range delegators { + if rewardShare == 0 { + return nil, ErrInvalidRewardDelegators( + DefaultCodespace, + "Reward share must be positive", + ) + } + + addr, err := sdk.AddressFromHex(addrStr) + if err != nil { + return nil, ErrInvalidRewardDelegators(DefaultCodespace, err.Error()) + } + + totalShares += uint64(rewardShare) + if totalShares > 100 { + return nil, ErrInvalidRewardDelegators( + DefaultCodespace, + fmt.Sprintf("Total share %d exceeds 100", totalShares), + ) + } + + normalized = append(normalized, AddressAndShare{ + Address: addr, + RewardShare: rewardShare, + }) + } + return normalized, nil +} + func (*MsgProtoStake) XXX_MessageName() string { return "x.nodes.MsgProtoStake8" } diff --git a/x/nodes/types/msg.pb.go b/x/nodes/types/msg.pb.go index 6c3439c83..eb8ec33d7 100644 --- a/x/nodes/types/msg.pb.go +++ b/x/nodes/types/msg.pb.go @@ -6,8 +6,8 @@ package types import ( bytes "bytes" fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" github_com_pokt_network_pocket_core_types "github.com/pokt-network/pocket-core/types" io "io" math "math" @@ -31,6 +31,8 @@ type MsgProtoStake struct { Value github_com_pokt_network_pocket_core_types.BigInt `protobuf:"bytes,3,opt,name=value,proto3,customtype=github.com/pokt-network/pocket-core/types.BigInt" json:"value" yaml:"value"` ServiceUrl string `protobuf:"bytes,4,opt,name=ServiceUrl,proto3" json:"service_url" yaml:"service_url"` OutputAddress github_com_pokt_network_pocket_core_types.Address `protobuf:"bytes,5,opt,name=OutputAddress,proto3,casttype=github.com/pokt-network/pocket-core/types.Address" json:"output_address,omitempty" yaml:"output_address"` + // Mapping from delegated-to addresses to a percentage of rewards. + RewardDelegators map[string]uint32 `protobuf:"bytes,6,rep,name=RewardDelegators,proto3" json:"reward_delegators,omitempty" yaml:"reward_delegators" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` } func (m *MsgProtoStake) Reset() { *m = MsgProtoStake{} } @@ -314,6 +316,7 @@ func (*MsgSend) XXX_MessageName() string { } func init() { proto.RegisterType((*MsgProtoStake)(nil), "x.nodes.MsgProtoStake") + proto.RegisterMapType((map[string]uint32)(nil), "x.nodes.MsgProtoStake.RewardDelegatorsEntry") proto.RegisterType((*LegacyMsgProtoStake)(nil), "x.nodes.LegacyMsgProtoStake") proto.RegisterType((*MsgBeginUnstake)(nil), "x.nodes.MsgBeginUnstake") proto.RegisterType((*LegacyMsgBeginUnstake)(nil), "x.nodes.LegacyMsgBeginUnstake") @@ -325,50 +328,56 @@ func init() { func init() { proto.RegisterFile("x/nodes/msg.proto", fileDescriptor_0de9b62fa75e413f) } var fileDescriptor_0de9b62fa75e413f = []byte{ - // 679 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcf, 0x6b, 0x13, 0x4f, - 0x1c, 0xcd, 0xa4, 0xdf, 0x26, 0x64, 0x9a, 0xb4, 0x74, 0xfb, 0x2d, 0x2c, 0x0a, 0x99, 0xb2, 0x22, - 0xf4, 0x60, 0x13, 0xa5, 0xb7, 0xde, 0x1a, 0x51, 0x10, 0x0d, 0xd6, 0xc4, 0x8a, 0x88, 0x50, 0xb7, - 0x9b, 0xe9, 0x74, 0xbb, 0x3f, 0x66, 0xd9, 0x99, 0x8d, 0xc9, 0x45, 0xc4, 0x53, 0x2f, 0x42, 0x8f, - 0x7a, 0x2b, 0x5e, 0xf4, 0x4f, 0x29, 0x78, 0xe9, 0xb1, 0x78, 0x18, 0xa4, 0xbd, 0xc8, 0x1e, 0x73, - 0x14, 0x0f, 0x92, 0x9d, 0xdd, 0x6e, 0x36, 0x07, 0x29, 0x29, 0xa8, 0x07, 0x6f, 0x99, 0xf7, 0x99, - 0x99, 0xf7, 0xf6, 0xbd, 0x4f, 0x3e, 0x0c, 0x9c, 0xef, 0xd5, 0x5d, 0xda, 0xc1, 0xac, 0xee, 0x30, - 0x52, 0xf3, 0x7c, 0xca, 0xa9, 0x52, 0xec, 0xd5, 0x22, 0xe8, 0xca, 0xff, 0x84, 0x12, 0x1a, 0x61, - 0xf5, 0xe1, 0x2f, 0x59, 0xd6, 0x4e, 0xa6, 0x60, 0xa5, 0xc9, 0xc8, 0xc6, 0x70, 0xd1, 0xe6, 0xba, - 0x85, 0x95, 0x75, 0x58, 0xda, 0x08, 0xb6, 0x6d, 0xd3, 0xb0, 0x70, 0x5f, 0x05, 0x4b, 0x60, 0xb9, - 0xdc, 0xb8, 0x16, 0x0a, 0x04, 0xbd, 0x08, 0xdc, 0xb2, 0x70, 0x7f, 0x20, 0xd0, 0x7c, 0x5f, 0x77, - 0xec, 0x35, 0x2d, 0xc5, 0xb4, 0x56, 0x7a, 0x4a, 0x59, 0x85, 0x85, 0xdb, 0xbb, 0xba, 0xe9, 0x32, - 0x35, 0xbf, 0x34, 0xb5, 0x5c, 0x6a, 0x5c, 0x0d, 0x05, 0x2a, 0x18, 0x11, 0x32, 0x10, 0xa8, 0x22, - 0xcf, 0xca, 0xb5, 0xd6, 0x8a, 0xb7, 0x2a, 0x04, 0x4e, 0x77, 0x75, 0x3b, 0xc0, 0xea, 0xd4, 0x12, - 0x58, 0x2e, 0x35, 0x1e, 0x1d, 0x09, 0x94, 0xfb, 0x22, 0xd0, 0x4d, 0x62, 0xf2, 0xdd, 0x60, 0xbb, - 0x66, 0x50, 0xa7, 0xee, 0x51, 0x8b, 0xaf, 0xb8, 0x98, 0xbf, 0xa4, 0xbe, 0x55, 0xf7, 0xa8, 0x61, - 0x61, 0xbe, 0x62, 0x50, 0x1f, 0xd7, 0x79, 0xdf, 0xc3, 0xac, 0xd6, 0x30, 0xc9, 0x3d, 0x97, 0x87, - 0x02, 0xc9, 0x8b, 0x06, 0x02, 0x95, 0x25, 0x55, 0xb4, 0xd4, 0x5a, 0x12, 0x56, 0xee, 0x40, 0xd8, - 0xc6, 0x7e, 0xd7, 0x34, 0xf0, 0xa6, 0x6f, 0xab, 0xff, 0x45, 0x6c, 0xd7, 0x43, 0x81, 0x66, 0x98, - 0x44, 0xb7, 0x02, 0xdf, 0x1e, 0x08, 0xa4, 0xc8, 0xb3, 0x23, 0xa0, 0xd6, 0x1a, 0x39, 0xa8, 0x1c, - 0x00, 0x58, 0x79, 0x18, 0x70, 0x2f, 0xe0, 0xeb, 0x9d, 0x8e, 0x8f, 0x19, 0x53, 0xa7, 0x23, 0xb3, - 0xf6, 0x42, 0x81, 0x54, 0x1a, 0x15, 0xb6, 0x74, 0x59, 0xb9, 0x41, 0x1d, 0x93, 0x63, 0xc7, 0xe3, - 0x43, 0xeb, 0x16, 0xe5, 0xbd, 0xd9, 0x1d, 0xda, 0x77, 0x81, 0x6e, 0x5d, 0xfc, 0x4b, 0x63, 0xc6, - 0x56, 0x56, 0xc0, 0x5a, 0x79, 0xff, 0x10, 0xe5, 0xde, 0x1d, 0x22, 0xf0, 0xed, 0x10, 0x01, 0xed, - 0x73, 0x1e, 0x2e, 0x3c, 0xc0, 0x44, 0x37, 0xfa, 0xff, 0x02, 0x9e, 0x20, 0xe0, 0x31, 0x37, 0x3f, - 0xe6, 0xe1, 0x5c, 0x93, 0x91, 0x06, 0x26, 0xa6, 0xbb, 0xe9, 0xb2, 0xc8, 0xc9, 0xd7, 0x00, 0x16, - 0x93, 0xf0, 0xa5, 0x91, 0x3b, 0xa1, 0x40, 0xf3, 0x5d, 0xdd, 0x36, 0x3b, 0x3a, 0xa7, 0x7e, 0x92, - 0xee, 0x40, 0x20, 0xf5, 0x5c, 0x68, 0xb6, 0x34, 0x61, 0xf0, 0x09, 0xad, 0xf2, 0x06, 0xc0, 0x42, - 0xdb, 0x24, 0x2e, 0xf6, 0xd5, 0x7c, 0xda, 0x7e, 0x2c, 0x42, 0x7e, 0xd5, 0x7e, 0xd9, 0x1d, 0x13, - 0xaa, 0x88, 0x99, 0xc7, 0x9c, 0xfa, 0x04, 0xe0, 0xe2, 0x79, 0xdf, 0xfd, 0x65, 0x7e, 0x8d, 0x49, - 0x7d, 0x9b, 0x87, 0xa5, 0x26, 0x23, 0x9b, 0xee, 0x9e, 0x6e, 0xda, 0x4a, 0x0f, 0x56, 0x9e, 0x24, - 0x7c, 0xc3, 0xfd, 0xb1, 0xc6, 0x56, 0x28, 0x50, 0x31, 0x55, 0x36, 0x2b, 0x95, 0x5d, 0xf2, 0x8f, - 0x9b, 0x21, 0x52, 0x7a, 0x63, 0x21, 0xbe, 0x08, 0x05, 0x9a, 0xcd, 0x46, 0xf4, 0x5b, 0xa2, 0x7b, - 0x0f, 0xe0, 0xdc, 0x79, 0x74, 0x7f, 0xda, 0x95, 0x31, 0x6d, 0x3f, 0xf2, 0xb0, 0xd8, 0x64, 0xa4, - 0x8d, 0xdd, 0x8e, 0xf2, 0x0a, 0xce, 0xdc, 0xf5, 0xa9, 0x93, 0xed, 0xa5, 0xe7, 0xa1, 0x40, 0xe5, - 0x1d, 0x9f, 0x3a, 0x23, 0x96, 0x2d, 0x48, 0x59, 0xa3, 0xe8, 0x84, 0xda, 0x46, 0x09, 0x95, 0x2e, - 0x2c, 0x3d, 0xa6, 0x09, 0xbb, 0x8c, 0xec, 0xe9, 0x70, 0x84, 0x72, 0x3a, 0xc2, 0x1d, 0x8f, 0xd0, - 0x14, 0x9b, 0x90, 0x39, 0xa5, 0x52, 0x2c, 0x58, 0xd0, 0x1d, 0x1a, 0xb8, 0x3c, 0x9e, 0xa1, 0xed, - 0x4b, 0xcc, 0xd0, 0xf8, 0xa6, 0x74, 0x5e, 0xcb, 0xb5, 0xd6, 0x8a, 0x0b, 0x6b, 0xe5, 0xc4, 0xfa, - 0xfd, 0x0f, 0x08, 0x34, 0xee, 0x1f, 0x9d, 0x56, 0xc1, 0xf1, 0x69, 0x15, 0x7c, 0x3d, 0xad, 0x82, - 0x83, 0xb3, 0x6a, 0xee, 0xf8, 0xac, 0x9a, 0x3b, 0x39, 0xab, 0xe6, 0x9e, 0x5d, 0xe8, 0x93, 0x92, - 0x87, 0x49, 0x24, 0x62, 0xbb, 0x10, 0x3d, 0x3e, 0x56, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x6a, - 0x0a, 0x12, 0xe0, 0xb0, 0x08, 0x00, 0x00, + // 776 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xbf, 0x6b, 0x1b, 0x49, + 0x14, 0xd6, 0x48, 0x67, 0x09, 0x8d, 0x25, 0xff, 0x18, 0xdb, 0xb0, 0xd8, 0xa0, 0x11, 0x7b, 0x1c, + 0xa8, 0xb0, 0xa5, 0xbb, 0x73, 0x73, 0xe8, 0x2a, 0xcb, 0x71, 0x20, 0x24, 0x22, 0xce, 0x2a, 0x0e, + 0x21, 0x04, 0x94, 0xb5, 0x34, 0x5e, 0xaf, 0xb5, 0xbb, 0x23, 0x76, 0x47, 0xb2, 0xd4, 0x84, 0x90, + 0xca, 0x4d, 0xc0, 0x4d, 0x20, 0xe9, 0x4c, 0x9a, 0xe4, 0x1f, 0xc8, 0xff, 0x60, 0x48, 0xe3, 0x32, + 0xa4, 0x18, 0x82, 0xdd, 0x84, 0x2d, 0x55, 0x86, 0x14, 0x41, 0x3b, 0xbb, 0x96, 0x56, 0x0e, 0xc1, + 0xc8, 0x90, 0xa4, 0x48, 0xb7, 0xf3, 0xbd, 0x37, 0xf3, 0x7d, 0xf3, 0xde, 0xb7, 0x8f, 0x81, 0xb3, + 0x9d, 0x82, 0x45, 0xeb, 0xc4, 0x29, 0x98, 0x8e, 0x96, 0x6f, 0xda, 0x94, 0x51, 0x94, 0xe8, 0xe4, + 0x3d, 0x68, 0x71, 0x5e, 0xa3, 0x1a, 0xf5, 0xb0, 0x42, 0xff, 0x4b, 0x84, 0xe5, 0xb7, 0x13, 0x30, + 0x5d, 0x76, 0xb4, 0xcd, 0xfe, 0xa2, 0xc2, 0xd4, 0x06, 0x41, 0x6b, 0x30, 0xb9, 0xd9, 0xda, 0x36, + 0xf4, 0x5a, 0x83, 0x74, 0x25, 0x90, 0x05, 0xb9, 0x54, 0xe9, 0x4f, 0x97, 0x63, 0xd8, 0xf4, 0xc0, + 0x6a, 0x83, 0x74, 0x7b, 0x1c, 0xcf, 0x76, 0x55, 0xd3, 0x28, 0xca, 0x03, 0x4c, 0x56, 0x06, 0xbb, + 0xd0, 0x2a, 0x8c, 0xaf, 0xef, 0xaa, 0xba, 0xe5, 0x48, 0xd1, 0x6c, 0x2c, 0x97, 0x2c, 0x2d, 0xb9, + 0x1c, 0xc7, 0x6b, 0x1e, 0xd2, 0xe3, 0x38, 0x2d, 0xf6, 0x8a, 0xb5, 0xac, 0xf8, 0xa9, 0x48, 0x83, + 0x13, 0x6d, 0xd5, 0x68, 0x11, 0x29, 0x96, 0x05, 0xb9, 0x64, 0xe9, 0xce, 0x31, 0xc7, 0x91, 0x0f, + 0x1c, 0xff, 0xad, 0xe9, 0x6c, 0xb7, 0xb5, 0x9d, 0xaf, 0x51, 0xb3, 0xd0, 0xa4, 0x0d, 0xb6, 0x62, + 0x11, 0xb6, 0x4f, 0xed, 0x46, 0xa1, 0x49, 0x6b, 0x0d, 0xc2, 0x56, 0x6a, 0xd4, 0x26, 0x05, 0xd6, + 0x6d, 0x12, 0x27, 0x5f, 0xd2, 0xb5, 0x1b, 0x16, 0x73, 0x39, 0x16, 0x07, 0xf5, 0x38, 0x4e, 0x09, + 0x2a, 0x6f, 0x29, 0x2b, 0x02, 0x46, 0x1b, 0x10, 0x56, 0x88, 0xdd, 0xd6, 0x6b, 0x64, 0xcb, 0x36, + 0xa4, 0x3f, 0x3c, 0xb6, 0xbf, 0x5c, 0x8e, 0x27, 0x1d, 0x81, 0x56, 0x5b, 0xb6, 0xd1, 0xe3, 0x18, + 0x89, 0xbd, 0x43, 0xa0, 0xac, 0x0c, 0x6d, 0x44, 0x87, 0x00, 0xa6, 0x6f, 0xb7, 0x58, 0xb3, 0xc5, + 0xd6, 0xea, 0x75, 0x9b, 0x38, 0x8e, 0x34, 0xe1, 0x15, 0x6b, 0xcf, 0xe5, 0x58, 0xa2, 0x5e, 0xa0, + 0xaa, 0x8a, 0xc8, 0x32, 0x35, 0x75, 0x46, 0xcc, 0x26, 0xeb, 0x97, 0x6e, 0x41, 0x9c, 0x1b, 0xce, + 0x90, 0x3f, 0x73, 0xfc, 0xcf, 0xe5, 0x6f, 0xea, 0x33, 0x2a, 0x61, 0x01, 0xe8, 0x39, 0x80, 0x33, + 0x0a, 0xd9, 0x57, 0xed, 0xfa, 0x35, 0x62, 0x10, 0x4d, 0x65, 0xd4, 0x76, 0xa4, 0x78, 0x36, 0x96, + 0x9b, 0xfc, 0x77, 0x39, 0xef, 0xfb, 0x20, 0x1f, 0xea, 0x76, 0x7e, 0x34, 0x7d, 0xc3, 0x62, 0x76, + 0xb7, 0xf4, 0xbf, 0xcb, 0xf1, 0x92, 0xed, 0x85, 0xaa, 0xf5, 0xf3, 0x58, 0xe8, 0x1a, 0x92, 0xb8, + 0xc6, 0x85, 0x24, 0x59, 0xb9, 0x20, 0x61, 0x71, 0x1d, 0x2e, 0x7c, 0x93, 0x07, 0xcd, 0xc0, 0x58, + 0xe0, 0xb2, 0xa4, 0xd2, 0xff, 0x44, 0xf3, 0x81, 0x0b, 0xa2, 0x59, 0x90, 0x4b, 0xfb, 0x2d, 0x2b, + 0x46, 0xff, 0x03, 0xc5, 0xd4, 0xc1, 0x11, 0x8e, 0xbc, 0x38, 0xc2, 0xe0, 0xd3, 0x11, 0x06, 0xf2, + 0xbb, 0x28, 0x9c, 0xbb, 0x45, 0x34, 0xb5, 0xd6, 0xfd, 0xed, 0xde, 0x31, 0xdc, 0x3b, 0x52, 0xcd, + 0xd7, 0x51, 0x38, 0x5d, 0x76, 0xb4, 0x12, 0xd1, 0x74, 0x6b, 0xcb, 0x72, 0xbc, 0x4a, 0x3e, 0x01, + 0x30, 0x11, 0x38, 0x5b, 0x14, 0x72, 0xc7, 0xe5, 0x78, 0xb6, 0xad, 0x1a, 0x7a, 0xbd, 0xdf, 0xc2, + 0xc0, 0xba, 0x03, 0x2f, 0x5c, 0x08, 0x8d, 0xe9, 0xea, 0x80, 0x16, 0x3d, 0x05, 0x30, 0x5e, 0xd1, + 0x35, 0x8b, 0xd8, 0x9e, 0x1d, 0xfc, 0x7f, 0xcb, 0xf1, 0x90, 0xef, 0xfd, 0x5b, 0xe1, 0x8c, 0x31, + 0x55, 0xf8, 0xcc, 0x23, 0x95, 0x7a, 0x03, 0xe0, 0xc2, 0xb9, 0xef, 0x7e, 0xb1, 0x7a, 0x8d, 0x48, + 0x7d, 0x16, 0x85, 0xc9, 0xb2, 0xa3, 0x6d, 0x59, 0x7b, 0xaa, 0x6e, 0xa0, 0x0e, 0x4c, 0xdf, 0x0b, + 0xf8, 0xfa, 0xf9, 0xbe, 0x46, 0xc5, 0xe5, 0x38, 0x31, 0x50, 0x36, 0x25, 0x94, 0x5d, 0x71, 0x2a, + 0x85, 0x88, 0x50, 0x67, 0xa4, 0x89, 0x8f, 0x5c, 0x8e, 0xa7, 0xc2, 0x2d, 0xfa, 0x21, 0xad, 0x7b, + 0x09, 0xe0, 0xf4, 0x79, 0xeb, 0x7e, 0x76, 0x55, 0x46, 0xb4, 0x7d, 0x89, 0xc2, 0x44, 0xd9, 0xd1, + 0x2a, 0xc4, 0xaa, 0xa3, 0xc7, 0x70, 0xf2, 0xba, 0x4d, 0xcd, 0xb0, 0x97, 0x1e, 0xba, 0x1c, 0xa7, + 0x76, 0x6c, 0x6a, 0x0e, 0x95, 0x6c, 0x4e, 0xc8, 0x1a, 0x46, 0xc7, 0xd4, 0x36, 0x4c, 0x88, 0xda, + 0x30, 0x79, 0x97, 0x06, 0xec, 0xa2, 0x65, 0xf7, 0xfb, 0x23, 0x94, 0xd1, 0x21, 0x6e, 0x7f, 0x84, + 0x0e, 0xb0, 0x31, 0x99, 0x07, 0x54, 0xa8, 0x01, 0xe3, 0xaa, 0x49, 0x5b, 0x16, 0xf3, 0x67, 0x68, + 0xe5, 0x0a, 0x33, 0xd4, 0x3f, 0x69, 0x30, 0xaf, 0xc5, 0x5a, 0x56, 0xfc, 0x40, 0x31, 0x15, 0x94, + 0xfe, 0xe0, 0x15, 0x06, 0xa5, 0x9b, 0xc7, 0xa7, 0x19, 0x70, 0x72, 0x9a, 0x01, 0x1f, 0x4f, 0x33, + 0xe0, 0xf0, 0x2c, 0x13, 0x39, 0x39, 0xcb, 0x44, 0xde, 0x9f, 0x65, 0x22, 0x0f, 0x2e, 0x75, 0xa5, + 0xe0, 0xd5, 0xe5, 0x89, 0xd8, 0x8e, 0x7b, 0x2f, 0xab, 0xd5, 0xaf, 0x01, 0x00, 0x00, 0xff, 0xff, + 0xea, 0x5e, 0x67, 0x4f, 0x8d, 0x09, 0x00, 0x00, } func (this *MsgProtoStake) Equal(that interface{}) bool { @@ -410,6 +419,14 @@ func (this *MsgProtoStake) Equal(that interface{}) bool { if !bytes.Equal(this.OutputAddress, that1.OutputAddress) { return false } + if len(this.RewardDelegators) != len(that1.RewardDelegators) { + return false + } + for i := range this.RewardDelegators { + if this.RewardDelegators[i] != that1.RewardDelegators[i] { + return false + } + } return true } func (this *LegacyMsgProtoStake) Equal(that interface{}) bool { @@ -602,6 +619,23 @@ func (m *MsgProtoStake) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.RewardDelegators) > 0 { + for k := range m.RewardDelegators { + v := m.RewardDelegators[k] + baseI := i + i = encodeVarintMsg(dAtA, i, uint64(v)) + i-- + dAtA[i] = 0x10 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintMsg(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintMsg(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x32 + } + } if len(m.OutputAddress) > 0 { i -= len(m.OutputAddress) copy(dAtA[i:], m.OutputAddress) @@ -919,6 +953,14 @@ func (m *MsgProtoStake) Size() (n int) { if l > 0 { n += 1 + l + sovMsg(uint64(l)) } + if len(m.RewardDelegators) > 0 { + for k, v := range m.RewardDelegators { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovMsg(uint64(len(k))) + 1 + sovMsg(uint64(v)) + n += mapEntrySize + 1 + sovMsg(uint64(mapEntrySize)) + } + } return n } @@ -1227,16 +1269,126 @@ func (m *MsgProtoStake) Unmarshal(dAtA []byte) error { m.OutputAddress = []byte{} } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardDelegators", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsg + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMsg + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMsg + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RewardDelegators == nil { + m.RewardDelegators = make(map[string]uint32) + } + var mapkey string + var mapvalue uint32 + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsg + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsg + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthMsg + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthMsg + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMsg + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapvalue |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + } else { + iNdEx = entryPreIndex + skippy, err := skipMsg(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMsg + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.RewardDelegators[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipMsg(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthMsg - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMsg } if (iNdEx + skippy) > l { @@ -1418,10 +1570,7 @@ func (m *LegacyMsgProtoStake) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthMsg - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMsg } if (iNdEx + skippy) > l { @@ -1539,10 +1688,7 @@ func (m *MsgBeginUnstake) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthMsg - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMsg } if (iNdEx + skippy) > l { @@ -1626,10 +1772,7 @@ func (m *LegacyMsgBeginUnstake) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthMsg - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMsg } if (iNdEx + skippy) > l { @@ -1747,10 +1890,7 @@ func (m *MsgUnjail) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthMsg - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMsg } if (iNdEx + skippy) > l { @@ -1834,10 +1974,7 @@ func (m *LegacyMsgUnjail) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthMsg - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMsg } if (iNdEx + skippy) > l { @@ -1989,10 +2126,7 @@ func (m *MsgSend) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthMsg - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMsg } if (iNdEx + skippy) > l { diff --git a/x/nodes/types/msg_test.go b/x/nodes/types/msg_test.go index 547fac188..21b14aaf4 100644 --- a/x/nodes/types/msg_test.go +++ b/x/nodes/types/msg_test.go @@ -1,13 +1,14 @@ package types import ( + "crypto/rand" "fmt" - "math/rand" "reflect" "testing" "github.com/pokt-network/pocket-core/crypto" sdk "github.com/pokt-network/pocket-core/types" + "github.com/stretchr/testify/assert" ) func TestMsgBeginUnstake_GetSignBytes(t *testing.T) { @@ -663,6 +664,54 @@ func TestMsgStake_ValidateBasic(t *testing.T) { } } +func TestMsgStake_Delegators(t *testing.T) { + operator := crypto.Ed25519PrivateKey{}.GenPrivateKey() + output := crypto.Ed25519PrivateKey{}.GenPrivateKey() + delegator1 := crypto.Ed25519PrivateKey{}.GenPrivateKey() + delegator2 := crypto.Ed25519PrivateKey{}.GenPrivateKey() + msg := MsgStake{ + PublicKey: operator.PublicKey(), + Chains: []string{"0001", "0040", "03DF"}, + Value: sdk.NewInt(1000000000000), + ServiceUrl: "https://pokt.network:1", + Output: sdk.Address(output.PublicKey().Address()), + RewardDelegators: nil, + } + assert.Nil(t, msg.ValidateBasic()) + + msg.RewardDelegators = map[string]uint32{} + + invalidAddr := "1234" + msg.RewardDelegators[invalidAddr] = 10 + err := msg.ValidateBasic() + assert.NotNil(t, err) + assert.Equal(t, CodeInvalidRewardDelegators, err.Code()) + + // RewardDelegators: {delegator1: 0} + delete(msg.RewardDelegators, invalidAddr) + msg.RewardDelegators[delegator1.PublicKey().Address().String()] = 0 + assert.NotNil(t, err) + assert.Equal(t, CodeInvalidRewardDelegators, err.Code()) + + // RewardDelegators: {delegator1: 100} + msg.RewardDelegators[delegator1.PublicKey().Address().String()] = 100 + assert.Nil(t, msg.ValidateBasic()) + + // Delegators: {delegator1: 100, delegator2: 1} + msg.RewardDelegators[delegator2.PubKey().Address().String()] = 1 + err = msg.ValidateBasic() + assert.NotNil(t, err) + assert.Equal(t, CodeInvalidRewardDelegators, err.Code()) + + // Delegators: {delegator1: 99, delegator2: 1} + msg.RewardDelegators[delegator1.PublicKey().Address().String()] = 99 + assert.Nil(t, msg.ValidateBasic()) + + // Delegators: {delegator1: 98, delegator2: 1} + msg.RewardDelegators[delegator1.PublicKey().Address().String()] = 98 + assert.Nil(t, msg.ValidateBasic()) +} + func TestMsgUnjail_GetSignBytes(t *testing.T) { type fields struct { ValidatorAddr sdk.Address diff --git a/x/nodes/types/nodes.pb.go b/x/nodes/types/nodes.pb.go index 42b287609..33e729066 100644 --- a/x/nodes/types/nodes.pb.go +++ b/x/nodes/types/nodes.pb.go @@ -6,10 +6,9 @@ package types import ( bytes "bytes" fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" - _ "github.com/golang/protobuf/ptypes/duration" _ "github.com/golang/protobuf/ptypes/timestamp" github_com_pokt_network_pocket_core_types "github.com/pokt-network/pocket-core/types" io "io" @@ -40,6 +39,7 @@ type ProtoValidator struct { StakedTokens github_com_pokt_network_pocket_core_types.BigInt `protobuf:"bytes,7,opt,name=StakedTokens,proto3,customtype=github.com/pokt-network/pocket-core/types.BigInt" json:"tokens"` UnstakingCompletionTime time.Time `protobuf:"bytes,8,opt,name=UnstakingCompletionTime,proto3,stdtime" json:"unstaking_time" yaml:"unstaking_time"` OutputAddress github_com_pokt_network_pocket_core_types.Address `protobuf:"bytes,9,opt,name=OutputAddress,proto3,casttype=github.com/pokt-network/pocket-core/types.Address" json:"output_address,omitempty" yaml:"output_address"` + RewardDelegators map[string]uint32 `protobuf:"bytes,10,rep,name=RewardDelegators,proto3" json:"reward_delegators,omitempty" yaml:"reward_delegators" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` } func (m *ProtoValidator) Reset() { *m = ProtoValidator{} } @@ -209,6 +209,7 @@ func (m *ValidatorSigningInfo) GetJailedBlocksCounter() int64 { func init() { proto.RegisterType((*ProtoValidator)(nil), "x.nodes.ProtoValidator") + proto.RegisterMapType((map[string]uint32)(nil), "x.nodes.ProtoValidator.RewardDelegatorsEntry") proto.RegisterType((*LegacyProtoValidator)(nil), "x.nodes.LegacyProtoValidator") proto.RegisterType((*ValidatorSigningInfo)(nil), "x.nodes.ValidatorSigningInfo") } @@ -216,55 +217,61 @@ func init() { func init() { proto.RegisterFile("x/nodes/nodes.proto", fileDescriptor_63cb49073b61e33a) } var fileDescriptor_63cb49073b61e33a = []byte{ - // 767 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x96, 0xbf, 0x6f, 0xf3, 0x44, - 0x18, 0xc7, 0x63, 0xda, 0x24, 0xcd, 0x25, 0x14, 0xe1, 0xb4, 0xc2, 0xaa, 0x50, 0x2e, 0x32, 0x03, - 0x19, 0x68, 0x0c, 0x74, 0xa2, 0x12, 0x12, 0x75, 0x17, 0x4a, 0x2b, 0x51, 0xb9, 0x2d, 0x43, 0x17, - 0xcb, 0xb1, 0x2f, 0xce, 0xd5, 0x3f, 0xce, 0xf2, 0x9d, 0xa1, 0xf9, 0x0f, 0x60, 0xeb, 0xd8, 0x31, - 0x7f, 0x4e, 0xc7, 0x2e, 0x48, 0x88, 0xe1, 0x40, 0xad, 0x84, 0x90, 0xc7, 0xb0, 0x31, 0x21, 0xdf, - 0x39, 0x24, 0xa9, 0xf2, 0xbe, 0xaa, 0xaa, 0x77, 0xec, 0x52, 0xfb, 0x3e, 0xf7, 0xdc, 0xf3, 0xbd, - 0xfa, 0xf9, 0x0c, 0x01, 0xed, 0x6b, 0x23, 0x26, 0x1e, 0xa2, 0xf2, 0x6f, 0x3f, 0x49, 0x09, 0x23, - 0x6a, 0xfd, 0xba, 0x2f, 0x96, 0x3b, 0x5b, 0x3e, 0xf1, 0x89, 0x60, 0x46, 0xf1, 0x26, 0xb7, 0x77, - 0xa0, 0x4f, 0x88, 0x1f, 0x22, 0x43, 0xac, 0x06, 0xd9, 0xd0, 0x60, 0x38, 0x42, 0x94, 0x39, 0x51, - 0x52, 0x16, 0x74, 0x9e, 0x16, 0x78, 0x59, 0xea, 0x30, 0x4c, 0x62, 0xb9, 0xaf, 0xff, 0x53, 0x05, - 0x9b, 0xa7, 0xc5, 0xdb, 0x0f, 0x4e, 0x88, 0x3d, 0x87, 0x91, 0x54, 0x0d, 0x41, 0xfd, 0xc0, 0xf3, - 0x52, 0x44, 0xa9, 0xa6, 0x74, 0x95, 0x5e, 0xcb, 0xb4, 0x72, 0x0e, 0xeb, 0x8e, 0x44, 0x53, 0x0e, - 0x37, 0xc7, 0x4e, 0x14, 0xee, 0xeb, 0x25, 0xd0, 0xff, 0xe5, 0xf0, 0x0b, 0x1f, 0xb3, 0x51, 0x36, - 0xe8, 0xbb, 0x24, 0x32, 0x12, 0x12, 0xb0, 0xdd, 0x18, 0xb1, 0x9f, 0x48, 0x1a, 0x18, 0x09, 0x71, - 0x03, 0xc4, 0x76, 0x5d, 0x92, 0x22, 0x83, 0x8d, 0x13, 0x44, 0xfb, 0x65, 0x67, 0x6b, 0x16, 0xa1, - 0x1e, 0x80, 0xc6, 0x69, 0x36, 0x08, 0xb1, 0x7b, 0x8c, 0xc6, 0xda, 0x7b, 0x22, 0xef, 0x93, 0x9c, - 0x43, 0x90, 0x08, 0x68, 0x07, 0x68, 0x3c, 0xe5, 0xf0, 0x43, 0x19, 0x39, 0x67, 0xba, 0x35, 0x3f, - 0xa5, 0xea, 0xa0, 0x76, 0xe5, 0xe0, 0x10, 0x79, 0xda, 0x5a, 0x57, 0xe9, 0x6d, 0x98, 0x20, 0xe7, - 0xb0, 0x24, 0x56, 0xf9, 0x2c, 0x6a, 0x28, 0x73, 0x58, 0x46, 0xb5, 0xf5, 0xae, 0xd2, 0xab, 0xca, - 0x1a, 0x49, 0xac, 0xf2, 0x59, 0xd4, 0x1c, 0x8e, 0x1c, 0x1c, 0x53, 0xad, 0xda, 0x5d, 0xeb, 0x35, - 0x64, 0x8d, 0x2b, 0x88, 0x55, 0xee, 0xa8, 0x06, 0x00, 0x67, 0x28, 0xfd, 0x11, 0xbb, 0xe8, 0xc2, - 0x3a, 0xd1, 0x6a, 0x5d, 0xa5, 0xd7, 0x30, 0x3f, 0xc8, 0x39, 0x6c, 0x52, 0x49, 0xed, 0x2c, 0x0d, - 0xad, 0x85, 0x12, 0x75, 0x08, 0x5a, 0x67, 0xcc, 0x09, 0x90, 0x77, 0x4e, 0x02, 0x14, 0x53, 0xad, - 0x2e, 0x8e, 0x98, 0x77, 0x1c, 0x56, 0x7e, 0xe7, 0xf0, 0xf3, 0xe7, 0x7f, 0x39, 0x13, 0xfb, 0x47, - 0x31, 0x2b, 0xae, 0xc4, 0x44, 0x27, 0x6b, 0xa9, 0xaf, 0xfa, 0x8b, 0x02, 0x3e, 0xba, 0x88, 0x29, - 0x73, 0x02, 0x1c, 0xfb, 0x87, 0x24, 0x4a, 0x42, 0x54, 0x8c, 0xf9, 0x1c, 0x47, 0x48, 0xdb, 0xe8, - 0x2a, 0xbd, 0xe6, 0x97, 0x3b, 0x7d, 0xe9, 0x42, 0x7f, 0xe6, 0x42, 0xff, 0x7c, 0x26, 0x8b, 0xb9, - 0x57, 0xdc, 0x27, 0xe7, 0x70, 0x33, 0x9b, 0xb5, 0xb0, 0x0b, 0x93, 0xa6, 0x1c, 0x6e, 0xcb, 0x4f, - 0xbf, 0xcc, 0xf5, 0x9b, 0x3f, 0xa0, 0x62, 0xbd, 0x29, 0x4f, 0xbd, 0x51, 0xc0, 0xfb, 0xdf, 0x67, - 0x2c, 0xc9, 0xd8, 0x4c, 0xa4, 0x86, 0x18, 0xec, 0x55, 0xce, 0xa1, 0x46, 0xc4, 0x86, 0x5d, 0xea, - 0xf3, 0x19, 0x89, 0x30, 0x43, 0x51, 0xc2, 0xc6, 0xf3, 0xac, 0xe5, 0x8a, 0x17, 0x0a, 0xb6, 0x7c, - 0x81, 0xfd, 0xd6, 0xcf, 0x13, 0x58, 0xb9, 0x9d, 0x40, 0xe5, 0xef, 0x09, 0x54, 0xf4, 0xbf, 0xd6, - 0xc1, 0xd6, 0x09, 0xf2, 0x1d, 0x77, 0xfc, 0xea, 0xfe, 0xab, 0xfb, 0xef, 0xd2, 0xfd, 0x27, 0xa2, - 0xfd, 0xba, 0x0e, 0xb6, 0xfe, 0xb7, 0xeb, 0x0c, 0xfb, 0x31, 0x8e, 0xfd, 0xa3, 0x78, 0x48, 0xd4, - 0x4b, 0x30, 0xb3, 0xaa, 0x14, 0xed, 0x9b, 0x05, 0xd1, 0x5e, 0xa8, 0x55, 0x79, 0x5a, 0xfd, 0x0e, - 0xb4, 0x28, 0x73, 0x52, 0x66, 0x8f, 0x10, 0xf6, 0x47, 0x4c, 0x98, 0xb5, 0x66, 0x7e, 0x9a, 0x73, - 0xb8, 0xc4, 0xa7, 0x1c, 0xb6, 0xe5, 0x3f, 0xb8, 0x48, 0x75, 0xab, 0x29, 0x96, 0xdf, 0x8a, 0x95, - 0xfa, 0x35, 0xa8, 0x1e, 0xc5, 0x1e, 0xba, 0x16, 0x7a, 0x95, 0x4d, 0x70, 0x01, 0x6c, 0x32, 0x1c, - 0x52, 0xb4, 0xd0, 0x64, 0x91, 0xea, 0x96, 0x3c, 0xa5, 0xc6, 0xa0, 0x25, 0x25, 0xb4, 0xb3, 0x98, - 0xe1, 0x50, 0x08, 0xf8, 0xf6, 0x69, 0x18, 0xe5, 0x34, 0x96, 0xce, 0xcd, 0x53, 0x16, 0xa9, 0x9c, - 0x44, 0x53, 0xa2, 0x8b, 0x82, 0xa8, 0x11, 0xd8, 0x8e, 0x30, 0xa5, 0xc8, 0xb3, 0x07, 0x21, 0x71, - 0x03, 0x6a, 0xbb, 0x24, 0x8b, 0x19, 0x4a, 0xb5, 0xaa, 0xb8, 0xfe, 0x57, 0x39, 0x87, 0xab, 0x0b, - 0xa6, 0x1c, 0x7e, 0x2c, 0x13, 0x56, 0x6e, 0xeb, 0x56, 0x5b, 0x72, 0x53, 0xe0, 0x43, 0x49, 0x8b, - 0xb8, 0xf2, 0x42, 0x4f, 0xe2, 0x6a, 0xf3, 0xb8, 0x95, 0x05, 0xf3, 0xb8, 0x95, 0xdb, 0xba, 0xd5, - 0x96, 0x7c, 0x29, 0x6e, 0x7f, 0xe3, 0x76, 0x02, 0x2b, 0x85, 0x57, 0xe6, 0xf1, 0xdd, 0x43, 0x47, - 0xb9, 0x7f, 0xe8, 0x28, 0x7f, 0x3e, 0x74, 0x94, 0x9b, 0xc7, 0x4e, 0xe5, 0xfe, 0xb1, 0x53, 0xf9, - 0xed, 0xb1, 0x53, 0xb9, 0x7c, 0x96, 0x38, 0xb3, 0x5f, 0x1a, 0x42, 0xa0, 0x41, 0x4d, 0x8c, 0x61, - 0xef, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x43, 0xc2, 0x5b, 0xa7, 0x81, 0x08, 0x00, 0x00, + // 858 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x96, 0xbf, 0x6f, 0xdb, 0x46, + 0x14, 0xc7, 0xc5, 0xc8, 0xb2, 0xac, 0x93, 0xe2, 0xa6, 0xb4, 0x8d, 0x12, 0x6e, 0xa1, 0x13, 0xd8, + 0xa1, 0x1a, 0x6a, 0xaa, 0x4d, 0x96, 0xd6, 0x45, 0x81, 0x86, 0x6e, 0x81, 0xba, 0x09, 0xd0, 0xe0, + 0x6c, 0x77, 0xc8, 0x42, 0x50, 0xe4, 0x89, 0xbe, 0xf0, 0xc7, 0x11, 0xbc, 0x63, 0x62, 0xfd, 0x07, + 0xed, 0xe6, 0xa9, 0xc8, 0xe8, 0x3f, 0x27, 0x63, 0x3a, 0x14, 0x28, 0x3a, 0x5c, 0x0b, 0x1b, 0x28, + 0x0a, 0x8e, 0x1a, 0x3b, 0x15, 0xbc, 0xa3, 0x22, 0xd1, 0x51, 0x8b, 0x20, 0xc8, 0x98, 0x45, 0xe4, + 0x7d, 0xdf, 0xbb, 0xf7, 0x7d, 0xc7, 0xfb, 0x3c, 0x40, 0x60, 0xeb, 0x6c, 0x94, 0x50, 0x1f, 0x33, + 0xf5, 0x6b, 0xa5, 0x19, 0xe5, 0x54, 0x6f, 0x9f, 0x59, 0x72, 0xb9, 0xbb, 0x1d, 0xd0, 0x80, 0x4a, + 0x6d, 0x54, 0xbe, 0xa9, 0xf0, 0x2e, 0x0c, 0x28, 0x0d, 0x22, 0x3c, 0x92, 0xab, 0x71, 0x3e, 0x19, + 0x71, 0x12, 0x63, 0xc6, 0xdd, 0x38, 0x55, 0x09, 0xe6, 0x2f, 0x6d, 0xb0, 0xf9, 0xa0, 0x7c, 0xfb, + 0xc1, 0x8d, 0x88, 0xef, 0x72, 0x9a, 0xe9, 0x11, 0x68, 0xdf, 0xf5, 0xfd, 0x0c, 0x33, 0x66, 0x68, + 0x03, 0x6d, 0xd8, 0xb3, 0x51, 0x21, 0x60, 0xdb, 0x55, 0xd2, 0x4c, 0xc0, 0xcd, 0xa9, 0x1b, 0x47, + 0xfb, 0x66, 0x25, 0x98, 0xff, 0x08, 0xf8, 0x69, 0x40, 0xf8, 0x69, 0x3e, 0xb6, 0x3c, 0x1a, 0x8f, + 0x52, 0x1a, 0xf2, 0xbd, 0x04, 0xf3, 0x27, 0x34, 0x0b, 0x47, 0x29, 0xf5, 0x42, 0xcc, 0xf7, 0x3c, + 0x9a, 0xe1, 0x11, 0x9f, 0xa6, 0x98, 0x59, 0x55, 0x65, 0x34, 0xb7, 0xd0, 0xef, 0x82, 0xce, 0x83, + 0x7c, 0x1c, 0x11, 0xef, 0x1e, 0x9e, 0x1a, 0x37, 0xa4, 0xdf, 0x87, 0x85, 0x80, 0x20, 0x95, 0xa2, + 0x13, 0xe2, 0xe9, 0x4c, 0xc0, 0x77, 0x95, 0xe5, 0x42, 0x33, 0xd1, 0x62, 0x97, 0x6e, 0x82, 0xf5, + 0x47, 0x2e, 0x89, 0xb0, 0x6f, 0x34, 0x07, 0xda, 0x70, 0xc3, 0x06, 0x85, 0x80, 0x95, 0x82, 0xaa, + 0x67, 0x99, 0xc3, 0xb8, 0xcb, 0x73, 0x66, 0xac, 0x0d, 0xb4, 0x61, 0x4b, 0xe5, 0x28, 0x05, 0x55, + 0xcf, 0x32, 0xe7, 0xe0, 0xd4, 0x25, 0x09, 0x33, 0x5a, 0x83, 0xe6, 0xb0, 0xa3, 0x72, 0x3c, 0xa9, + 0xa0, 0x2a, 0xa2, 0x8f, 0x00, 0x38, 0xc2, 0xd9, 0x63, 0xe2, 0xe1, 0x13, 0x74, 0xdf, 0x58, 0x1f, + 0x68, 0xc3, 0x8e, 0xfd, 0x4e, 0x21, 0x60, 0x97, 0x29, 0xd5, 0xc9, 0xb3, 0x08, 0x2d, 0xa5, 0xe8, + 0x13, 0xd0, 0x3b, 0xe2, 0x6e, 0x88, 0xfd, 0x63, 0x1a, 0xe2, 0x84, 0x19, 0x6d, 0xb9, 0xc5, 0x7e, + 0x26, 0x60, 0xe3, 0x77, 0x01, 0x3f, 0x79, 0xf5, 0x2f, 0x67, 0x93, 0xe0, 0x30, 0xe1, 0x65, 0x4b, + 0x5c, 0x56, 0x42, 0xb5, 0xba, 0xfa, 0x4f, 0x1a, 0x78, 0xef, 0x24, 0x61, 0xdc, 0x0d, 0x49, 0x12, + 0x1c, 0xd0, 0x38, 0x8d, 0x30, 0x27, 0x34, 0x39, 0x26, 0x31, 0x36, 0x36, 0x06, 0xda, 0xb0, 0x7b, + 0x7b, 0xd7, 0x52, 0x30, 0x58, 0x73, 0x18, 0xac, 0xe3, 0x39, 0x0c, 0xf6, 0x9d, 0xb2, 0x9f, 0x42, + 0xc0, 0xcd, 0x7c, 0x5e, 0xc2, 0x29, 0x49, 0x99, 0x09, 0xb8, 0xa3, 0x3e, 0x7d, 0x5d, 0x37, 0xcf, + 0xff, 0x80, 0x1a, 0xfa, 0x2f, 0x3f, 0xfd, 0x5c, 0x03, 0x37, 0xbf, 0xcf, 0x79, 0x9a, 0xf3, 0x39, + 0x48, 0x1d, 0x79, 0xb1, 0x8f, 0x0a, 0x01, 0x0d, 0x2a, 0x03, 0x4e, 0x85, 0xcf, 0xc7, 0x34, 0x26, + 0x1c, 0xc7, 0x29, 0x9f, 0x2e, 0xbc, 0xea, 0x19, 0xaf, 0x09, 0x58, 0xbd, 0x01, 0xfd, 0x67, 0x0d, + 0xdc, 0x42, 0xf8, 0x89, 0x9b, 0xf9, 0x5f, 0xe3, 0x08, 0x07, 0x25, 0xe8, 0xcc, 0x00, 0x83, 0xe6, + 0xb0, 0x7b, 0x7b, 0xcf, 0xaa, 0x66, 0xc8, 0xaa, 0x0f, 0x82, 0x75, 0x3d, 0xff, 0x9b, 0x84, 0x67, + 0x53, 0xfb, 0x8b, 0x42, 0xc0, 0xf7, 0x33, 0x19, 0x72, 0xfc, 0x17, 0xb1, 0xda, 0x39, 0x0c, 0x75, + 0x8e, 0x97, 0x92, 0x4c, 0xf4, 0x52, 0x0f, 0xbb, 0x07, 0x60, 0x67, 0xa5, 0x8f, 0x7e, 0x0b, 0x34, + 0x43, 0x3c, 0x95, 0x23, 0xd8, 0x41, 0xe5, 0xab, 0xbe, 0x0d, 0x5a, 0x8f, 0xdd, 0x28, 0xc7, 0x72, + 0x4c, 0x6e, 0x22, 0xb5, 0xd8, 0xbf, 0xf1, 0x99, 0xb6, 0xdf, 0xfb, 0xf1, 0x02, 0x36, 0x9e, 0x5e, + 0x40, 0xed, 0xef, 0x0b, 0xa8, 0x99, 0x7f, 0xad, 0x81, 0xed, 0xfb, 0x38, 0x70, 0xbd, 0xe9, 0xdb, + 0xc9, 0x7e, 0x3b, 0xd9, 0x6f, 0x72, 0xb2, 0xaf, 0x81, 0xf6, 0xeb, 0x1a, 0xd8, 0x7e, 0x41, 0xd7, + 0x11, 0x09, 0x12, 0x92, 0x04, 0x87, 0xc9, 0x84, 0xea, 0x0f, 0xc1, 0x9c, 0xaa, 0x0a, 0xb4, 0xaf, + 0x96, 0x40, 0x7b, 0x4d, 0xac, 0xaa, 0xdd, 0xfa, 0x77, 0xa0, 0xc7, 0xb8, 0x9b, 0x71, 0xe7, 0x14, + 0x93, 0xe0, 0x94, 0x4b, 0xb2, 0x9a, 0xf6, 0x47, 0x85, 0x80, 0x35, 0x7d, 0x26, 0xe0, 0x96, 0x3a, + 0xe0, 0xb2, 0x6a, 0xa2, 0xae, 0x5c, 0x7e, 0x2b, 0x57, 0xfa, 0x97, 0xa0, 0x75, 0x98, 0xf8, 0xf8, + 0x4c, 0xe2, 0x55, 0x15, 0x21, 0xa5, 0xe0, 0xd0, 0xc9, 0x84, 0xe1, 0xa5, 0x22, 0xcb, 0xaa, 0x89, + 0xd4, 0x2e, 0x3d, 0x01, 0x3d, 0x05, 0xa1, 0x93, 0x27, 0x9c, 0x44, 0x12, 0xc0, 0xff, 0xbf, 0x8d, + 0x51, 0x75, 0x1b, 0xb5, 0x7d, 0x0b, 0x97, 0x65, 0x55, 0xdd, 0x44, 0x57, 0x49, 0x27, 0xa5, 0xa2, + 0xc7, 0x60, 0x27, 0x26, 0x8c, 0x61, 0xdf, 0x19, 0x47, 0xd4, 0x0b, 0x99, 0xe3, 0xd1, 0x3c, 0xe1, + 0x38, 0x33, 0x5a, 0xb2, 0xfd, 0xcf, 0x0b, 0x01, 0x57, 0x27, 0xcc, 0x04, 0xfc, 0x40, 0x39, 0xac, + 0x0c, 0x9b, 0x68, 0x4b, 0xe9, 0xb6, 0x94, 0x0f, 0x94, 0x5a, 0xda, 0x55, 0x0d, 0x5d, 0xb3, 0x5b, + 0x5f, 0xd8, 0xad, 0x4c, 0x58, 0xd8, 0xad, 0x0c, 0x9b, 0x68, 0x4b, 0xe9, 0x35, 0xbb, 0xfd, 0x8d, + 0xa7, 0x17, 0xb0, 0x51, 0x72, 0x65, 0xdf, 0x7b, 0x76, 0xd9, 0xd7, 0x9e, 0x5f, 0xf6, 0xb5, 0x3f, + 0x2f, 0xfb, 0xda, 0xf9, 0x55, 0xbf, 0xf1, 0xfc, 0xaa, 0xdf, 0xf8, 0xed, 0xaa, 0xdf, 0x78, 0xf8, + 0x4a, 0xe0, 0xcc, 0xff, 0x27, 0x49, 0x80, 0xc6, 0xeb, 0xf2, 0x1a, 0xee, 0xfc, 0x1b, 0x00, 0x00, + 0xff, 0xff, 0x49, 0xf4, 0x43, 0x35, 0x3f, 0x09, 0x00, 0x00, } func (this *ProtoValidator) Equal(that interface{}) bool { @@ -318,6 +325,14 @@ func (this *ProtoValidator) Equal(that interface{}) bool { if !bytes.Equal(this.OutputAddress, that1.OutputAddress) { return false } + if len(this.RewardDelegators) != len(that1.RewardDelegators) { + return false + } + for i := range this.RewardDelegators { + if this.RewardDelegators[i] != that1.RewardDelegators[i] { + return false + } + } return true } func (this *LegacyProtoValidator) Equal(that interface{}) bool { @@ -429,6 +444,23 @@ func (m *ProtoValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.RewardDelegators) > 0 { + for k := range m.RewardDelegators { + v := m.RewardDelegators[k] + baseI := i + i = encodeVarintNodes(dAtA, i, uint64(v)) + i-- + dAtA[i] = 0x10 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintNodes(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintNodes(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x52 + } + } if len(m.OutputAddress) > 0 { i -= len(m.OutputAddress) copy(dAtA[i:], m.OutputAddress) @@ -436,7 +468,7 @@ func (m *ProtoValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x4a } - n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UnstakingCompletionTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UnstakingCompletionTime):]) + n1, err1 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.UnstakingCompletionTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.UnstakingCompletionTime):]) if err1 != nil { return 0, err1 } @@ -522,7 +554,7 @@ func (m *LegacyProtoValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UnstakingCompletionTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UnstakingCompletionTime):]) + n2, err2 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.UnstakingCompletionTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.UnstakingCompletionTime):]) if err2 != nil { return 0, err2 } @@ -618,7 +650,7 @@ func (m *ValidatorSigningInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.JailedUntil, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.JailedUntil):]) + n3, err3 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.JailedUntil, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.JailedUntil):]) if err3 != nil { return 0, err3 } @@ -689,12 +721,20 @@ func (m *ProtoValidator) Size() (n int) { } l = m.StakedTokens.Size() n += 1 + l + sovNodes(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UnstakingCompletionTime) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.UnstakingCompletionTime) n += 1 + l + sovNodes(uint64(l)) l = len(m.OutputAddress) if l > 0 { n += 1 + l + sovNodes(uint64(l)) } + if len(m.RewardDelegators) > 0 { + for k, v := range m.RewardDelegators { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovNodes(uint64(len(k))) + 1 + sovNodes(uint64(v)) + n += mapEntrySize + 1 + sovNodes(uint64(mapEntrySize)) + } + } return n } @@ -730,7 +770,7 @@ func (m *LegacyProtoValidator) Size() (n int) { } l = m.StakedTokens.Size() n += 1 + l + sovNodes(uint64(l)) - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UnstakingCompletionTime) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.UnstakingCompletionTime) n += 1 + l + sovNodes(uint64(l)) return n } @@ -751,7 +791,7 @@ func (m *ValidatorSigningInfo) Size() (n int) { if m.Index != 0 { n += 1 + sovNodes(uint64(m.Index)) } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.JailedUntil) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.JailedUntil) n += 1 + l + sovNodes(uint64(l)) if m.MissedBlocksCounter != 0 { n += 1 + sovNodes(uint64(m.MissedBlocksCounter)) @@ -1031,7 +1071,7 @@ func (m *ProtoValidator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UnstakingCompletionTime, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.UnstakingCompletionTime, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1069,16 +1109,126 @@ func (m *ProtoValidator) Unmarshal(dAtA []byte) error { m.OutputAddress = []byte{} } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardDelegators", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNodes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthNodes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNodes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RewardDelegators == nil { + m.RewardDelegators = make(map[string]uint32) + } + var mapkey string + var mapvalue uint32 + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNodes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNodes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthNodes + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthNodes + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNodes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapvalue |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + } else { + iNdEx = entryPreIndex + skippy, err := skipNodes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNodes + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.RewardDelegators[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipNodes(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthNodes - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNodes } if (iNdEx + skippy) > l { @@ -1356,7 +1506,7 @@ func (m *LegacyProtoValidator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UnstakingCompletionTime, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.UnstakingCompletionTime, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1366,10 +1516,7 @@ func (m *LegacyProtoValidator) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthNodes - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNodes } if (iNdEx + skippy) > l { @@ -1514,7 +1661,7 @@ func (m *ValidatorSigningInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.JailedUntil, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.JailedUntil, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1562,10 +1709,7 @@ func (m *ValidatorSigningInfo) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthNodes - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNodes } if (iNdEx + skippy) > l { diff --git a/x/nodes/types/params_test.go b/x/nodes/types/params_test.go index 03d8639c3..36a7fde9e 100644 --- a/x/nodes/types/params_test.go +++ b/x/nodes/types/params_test.go @@ -16,22 +16,23 @@ func TestDefaultParams(t *testing.T) { }{ {"Default Test", Params{ - UnstakingTime: DefaultUnstakingTime, - MaxValidators: DefaultMaxValidators, - StakeMinimum: DefaultMinStake, - StakeDenom: types.DefaultStakeDenom, - MaxEvidenceAge: DefaultMaxEvidenceAge, - SignedBlocksWindow: DefaultSignedBlocksWindow, - MinSignedPerWindow: DefaultMinSignedPerWindow, - DowntimeJailDuration: DefaultDowntimeJailDuration, - SlashFractionDoubleSign: DefaultSlashFractionDoubleSign, - SlashFractionDowntime: DefaultSlashFractionDowntime, - SessionBlockFrequency: DefaultSessionBlocktime, - DAOAllocation: DefaultDAOAllocation, - ProposerAllocation: DefaultProposerAllocation, - RelaysToTokensMultiplier: DefaultRelaysToTokensMultiplier, - MaximumChains: DefaultMaxChains, - MaxJailedBlocks: DefaultMaxJailedBlocks, + UnstakingTime: DefaultUnstakingTime, + MaxValidators: DefaultMaxValidators, + StakeMinimum: DefaultMinStake, + StakeDenom: types.DefaultStakeDenom, + MaxEvidenceAge: DefaultMaxEvidenceAge, + SignedBlocksWindow: DefaultSignedBlocksWindow, + MinSignedPerWindow: DefaultMinSignedPerWindow, + DowntimeJailDuration: DefaultDowntimeJailDuration, + SlashFractionDoubleSign: DefaultSlashFractionDoubleSign, + SlashFractionDowntime: DefaultSlashFractionDowntime, + SessionBlockFrequency: DefaultSessionBlocktime, + DAOAllocation: DefaultDAOAllocation, + ProposerAllocation: DefaultProposerAllocation, + RelaysToTokensMultiplier: DefaultRelaysToTokensMultiplier, + MaximumChains: DefaultMaxChains, + MaxJailedBlocks: DefaultMaxJailedBlocks, + RelaysToTokensMultiplierMap: DefaultRelaysToTokensMultiplierMap, }, }} for _, tt := range tests { diff --git a/x/nodes/types/util.go b/x/nodes/types/util.go index a02ecfe19..e48ae885b 100644 --- a/x/nodes/types/util.go +++ b/x/nodes/types/util.go @@ -3,10 +3,11 @@ package types import ( "encoding/hex" "fmt" - sdk "github.com/pokt-network/pocket-core/types" "net/url" "strconv" "strings" + + sdk "github.com/pokt-network/pocket-core/types" ) // TODO shared code among modules below @@ -65,3 +66,33 @@ func ValidateNetworkIdentifier(chain string) sdk.Error { } return nil } + +func CompareSlices[T comparable](a, b []T) bool { + if len(a) != len(b) { + return false + } + + for i, elem := range a { + if elem != b[i] { + return false + } + } + + return true +} + +// True if two maps are equivalent. +// Nil is considered to be the same as an empty map. +func CompareStringMaps[T comparable](a, b map[string]T) bool { + if len(a) != len(b) { + return false + } + + for k, v := range a { + if v != b[k] { + return false + } + } + + return true +} diff --git a/x/nodes/types/util_test.go b/x/nodes/types/util_test.go index 58cbe0574..e1009de3c 100644 --- a/x/nodes/types/util_test.go +++ b/x/nodes/types/util_test.go @@ -1,8 +1,9 @@ package types import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestValidateServiceURL(t *testing.T) { @@ -24,3 +25,43 @@ func TestValidateServiceURL(t *testing.T) { assert.NotNil(t, ValidateServiceURL(invalidURLBadPort), "invalid bad port") assert.NotNil(t, ValidateServiceURL(invalidURLBad), "invalid bad url") } + +func TestCompareSlices(t *testing.T) { + assert.True(t, CompareSlices([]string{"1"}, []string{"1"})) + assert.True(t, CompareSlices([]int{3, 1}, []int{3, 1})) + assert.False(t, CompareSlices([]int{3, 1}, []int{3, 2})) + assert.False(t, CompareSlices([]int{3, 1}, []int{3})) + + // Empty and nil slices are identical + assert.True(t, CompareSlices([]int{}, nil)) + assert.True(t, CompareSlices(nil, []int{})) + assert.True(t, CompareSlices([]int{}, []int{})) +} + +func TestCompareStringMaps(t *testing.T) { + m1 := map[string]int{} + m2 := map[string]int{} + assert.True(t, CompareStringMaps(m1, m2)) + + // m1 is non-empty and m2 is empty + m1["a"] = 10 + m1["b"] = 100 + assert.False(t, CompareStringMaps(m1, m2)) + + // m1 and m2 are not empty and identical + m2["b"] = 100 + m2["a"] = 10 + assert.True(t, CompareStringMaps(m2, m1)) + + // m1 is non-empty and m2 is nil + m2 = nil + assert.False(t, CompareStringMaps(m1, m2)) + assert.False(t, CompareStringMaps(nil, m1)) + + // m1 and m2 are both nil + m1 = nil + assert.True(t, CompareStringMaps(m1, m2)) + + // Empty and nil maps are identical + assert.True(t, CompareStringMaps(nil, map[string]int{})) +} diff --git a/x/nodes/types/validator.go b/x/nodes/types/validator.go index 1d8228d7e..7f526e5af 100644 --- a/x/nodes/types/validator.go +++ b/x/nodes/types/validator.go @@ -4,12 +4,11 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/pokt-network/pocket-core/codec" "strings" "time" + "github.com/pokt-network/pocket-core/codec" "github.com/pokt-network/pocket-core/crypto" - sdk "github.com/pokt-network/pocket-core/types" abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" @@ -25,6 +24,8 @@ type Validator struct { StakedTokens sdk.BigInt `json:"tokens" yaml:"tokens"` // tokens staked in the network UnstakingCompletionTime time.Time `json:"unstaking_time" yaml:"unstaking_time"` // if unstaking, min time for the validator to complete unstaking OutputAddress sdk.Address `json:"output_address,omitempty" yaml:"output_address"` // the custodial output address of the validator + // Mapping from delegated-to addresses to a percentage of rewards + RewardDelegators map[string]uint32 `json:"reward_delegators,omitempty" yaml:"reward_delegators"` } // NewValidator - initialize a new validator @@ -42,6 +43,21 @@ func NewValidator(addr sdk.Address, consPubKey crypto.PublicKey, chains []string } } +func NewValidatorFromMsg(msg MsgStake) Validator { + return Validator{ + Address: sdk.Address(msg.PublicKey.Address()), + PublicKey: msg.PublicKey, + Jailed: false, + Status: sdk.Staked, + Chains: msg.Chains, + ServiceURL: msg.ServiceUrl, + StakedTokens: msg.Value, + UnstakingCompletionTime: time.Time{}, + OutputAddress: msg.Output, + RewardDelegators: msg.RewardDelegators, + } +} + // ABCIValidatorUpdate returns an abci.ValidatorUpdate from a staking validator type // with the full validator power func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate { @@ -114,7 +130,6 @@ func (v Validator) HasChain(netID string) bool { return false } -// return the TM validator address func (v Validator) GetChains() []string { return v.Chains } func (v Validator) GetServiceURL() string { return v.ServiceURL } func (v Validator) IsStaked() bool { return v.GetStatus().Equal(sdk.Staked) } @@ -169,10 +184,37 @@ func (v Validator) String() string { if v.OutputAddress != nil { outputPubKeyString = v.OutputAddress.String() } - return fmt.Sprintf("Address:\t\t%s\nPublic Key:\t\t%s\nJailed:\t\t\t%v\nStatus:\t\t\t%s\nTokens:\t\t\t%s\n"+ - "ServiceUrl:\t\t%s\nChains:\t\t\t%v\nUnstaking Completion Time:\t\t%v\nOutput Address:\t\t%s"+ - "\n----\n", - v.Address, v.PublicKey.RawString(), v.Jailed, v.Status, v.StakedTokens, v.ServiceURL, v.Chains, v.UnstakingCompletionTime, outputPubKeyString, + delegatorsStr := "" + if v.RewardDelegators != nil { + if jsonBytes, err := json.Marshal(v.RewardDelegators); err == nil { + delegatorsStr = string(jsonBytes) + } else { + delegatorsStr = err.Error() + } + } + return fmt.Sprintf( + `Address: %s +Public Key: %s +Jailed: %v +Status: %s +Tokens: %s +ServiceUrl: %s +Chains: %v +Unstaking Completion Time: %v +Output Address: %s +Reward Delegators: %s +---- +`, + v.Address, + v.PublicKey.RawString(), + v.Jailed, + v.Status, + v.StakedTokens, + v.ServiceURL, + v.Chains, + v.UnstakingCompletionTime, + outputPubKeyString, + delegatorsStr, ) } @@ -190,6 +232,7 @@ func (v Validator) MarshalJSON() ([]byte, error) { StakedTokens: v.StakedTokens, UnstakingCompletionTime: v.UnstakingCompletionTime, OutputAddress: v.OutputAddress, + RewardDelegators: v.RewardDelegators, }) } @@ -213,6 +256,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { Status: bv.Status, UnstakingCompletionTime: bv.UnstakingCompletionTime, OutputAddress: bv.OutputAddress, + RewardDelegators: bv.RewardDelegators, } return nil } @@ -233,6 +277,7 @@ func (v ProtoValidator) FromProto() (Validator, error) { StakedTokens: v.StakedTokens, UnstakingCompletionTime: v.UnstakingCompletionTime, OutputAddress: v.OutputAddress, + RewardDelegators: v.RewardDelegators, }, nil } @@ -248,6 +293,7 @@ func (v Validator) ToProto() ProtoValidator { StakedTokens: v.StakedTokens, UnstakingCompletionTime: v.UnstakingCompletionTime, OutputAddress: v.OutputAddress, + RewardDelegators: v.RewardDelegators, } } @@ -261,6 +307,8 @@ type JSONValidator struct { StakedTokens sdk.BigInt `json:"tokens" yaml:"tokens"` // tokens staked in the network UnstakingCompletionTime time.Time `json:"unstaking_time" yaml:"unstaking_time"` // if unstaking, min time for the validator to complete unstaking OutputAddress sdk.Address `json:"output_address" yaml:"output_address"` // custodial output address of tokens + // Mapping from delegated-to addresses to a percentage of rewards + RewardDelegators map[string]uint32 `json:"reward_delegators" yaml:"reward_delegators"` } // Validators is a collection of Validator diff --git a/x/nodes/types/validator_legacy.go b/x/nodes/types/validator_legacy.go index ee7c825b7..6b7ac615a 100644 --- a/x/nodes/types/validator_legacy.go +++ b/x/nodes/types/validator_legacy.go @@ -2,12 +2,14 @@ package types import ( "fmt" + "time" + "github.com/pokt-network/pocket-core/codec" "github.com/pokt-network/pocket-core/crypto" sdk "github.com/pokt-network/pocket-core/types" - "time" ) +// Compilation level enforcement to validate that structs implement ProtoMarshaler var _ codec.ProtoMarshaler = &LegacyValidator{} type LegacyValidator struct { @@ -21,6 +23,17 @@ type LegacyValidator struct { UnstakingCompletionTime time.Time `json:"unstaking_time" yaml:"unstaking_time"` // if unstaking, min time for the validator to complete unstaking } +func (v LegacyValidator) Equals(v2 LegacyValidator) bool { + return v.Address.Equals(v2.Address) && + v.PublicKey.Equals(v2.PublicKey) && + v.Jailed == v2.Jailed && + v.Status == v2.Status && + CompareSlices(v.Chains, v2.Chains) && + v.ServiceURL == v2.ServiceURL && + v.StakedTokens.Equal(v2.StakedTokens) && + v.UnstakingCompletionTime.Equal(v2.UnstakingCompletionTime) +} + func (v *LegacyValidator) Marshal() ([]byte, error) { a := v.ToProto() return a.Marshal() @@ -106,10 +119,24 @@ func (v *LegacyValidator) Reset() { } func (v LegacyValidator) String() string { - return fmt.Sprintf("Address:\t\t%s\nPublic Key:\t\t%s\nJailed:\t\t\t%v\nStatus:\t\t\t%s\nTokens:\t\t\t%s\n"+ - "ServiceUrl:\t\t%s\nChains:\t\t\t%v\nUnstaking Completion Time:\t\t%v\n"+ - "\n----\n", - v.Address, v.PublicKey.RawString(), v.Jailed, v.Status, v.StakedTokens, v.ServiceURL, v.Chains, v.UnstakingCompletionTime, + return fmt.Sprintf(`Address: %s +Public Key: %s +Jailed: %v +Status: %s +Tokens: %s +ServiceUrl: %s +Chains: %v +Unstaking Completion Time: %v +---- +`, + v.Address, + v.PublicKey.RawString(), + v.Jailed, + v.Status, + v.StakedTokens, + v.ServiceURL, + v.Chains, + v.UnstakingCompletionTime, ) } @@ -129,6 +156,7 @@ func (v LegacyValidator) ToValidator() Validator { StakedTokens: v.StakedTokens, UnstakingCompletionTime: v.UnstakingCompletionTime, OutputAddress: nil, + RewardDelegators: nil, } } diff --git a/x/nodes/types/validator_test.go b/x/nodes/types/validator_test.go index 822821aa7..f27808733 100644 --- a/x/nodes/types/validator_test.go +++ b/x/nodes/types/validator_test.go @@ -2,8 +2,6 @@ package types import ( "fmt" - "github.com/stretchr/testify/assert" - "github.com/tendermint/go-amino" "math/rand" "reflect" "testing" @@ -11,6 +9,8 @@ import ( "github.com/pokt-network/pocket-core/crypto" sdk "github.com/pokt-network/pocket-core/types" + "github.com/stretchr/testify/assert" + "github.com/tendermint/go-amino" abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" ) @@ -1156,6 +1156,7 @@ func TestValidators_String(t *testing.T) { }{ {"String Test", v, fmt.Sprintf("Address:\t\t%s\nPublic Key:\t\t%s\nJailed:\t\t\t%v\nStatus:\t\t\t%s\nTokens:\t\t\t%s\n"+ "ServiceUrl:\t\t%s\nChains:\t\t\t%v\nUnstaking Completion Time:\t\t%v\nOutput Address:\t\t%s"+ + "\nReward Delegators:\t\t"+ "\n----", sdk.Address(pub.Address()), pub.RawString(), false, sdk.Staked, sdk.ZeroInt(), "https://www.google.com:443", []string{"0001"}, time.Unix(0, 0).UTC(), "", )}, diff --git a/x/pocketcore/keeper/claim.go b/x/pocketcore/keeper/claim.go index 5ee12187d..79a52f896 100644 --- a/x/pocketcore/keeper/claim.go +++ b/x/pocketcore/keeper/claim.go @@ -5,14 +5,13 @@ import ( "fmt" "time" - "github.com/tendermint/tendermint/rpc/client" - "github.com/pokt-network/pocket-core/codec" "github.com/pokt-network/pocket-core/crypto" sdk "github.com/pokt-network/pocket-core/types" "github.com/pokt-network/pocket-core/x/auth" "github.com/pokt-network/pocket-core/x/auth/util" pc "github.com/pokt-network/pocket-core/x/pocketcore/types" + "github.com/tendermint/tendermint/rpc/client" ) // "SendClaimTx" - Automatically sends a claim of work/challenge based on relays or challenges stored. @@ -25,6 +24,9 @@ func (k Keeper) SendClaimTx( ) { // get the private val key (main) account from the keybase address := node.GetAddress() + validator := k.posKeeper.Validator(ctx, address) + // get the cost to earn relay rewards + rewardCost := k.posKeeper.GetRewardCost(ctx) // retrieve the iterator to go through each piece of evidence in storage iter := pc.EvidenceIterator(node.EvidenceStore) defer iter.Close() @@ -52,6 +54,40 @@ func (k Keeper) SendClaimTx( } continue } + if validator != nil && pc.GlobalPocketConfig.PreventNegativeRewardClaim { + rewardExpected, _ := k.posKeeper.CalculateRelayReward( + ctx, + evidence.Chain, + sdk.NewInt(evidence.NumOfProofs), + validator.GetTokens(), + ) + if rewardExpected.LTE(rewardCost) { + // If the expected amount of relay rewards from this evidence is less + // than the cost of claiming/proofing the evidence, claiming the + // evidence is a potential loss. + // + // It's still "potential" because the amount of relay rewards is + // calculated when the network processes a proof transaction. It's + // possible this evidence is profitable if RTTM is increased and/or + // the node's stake is increased to an upper bin. + ctx.Logger().Info("Discarding an evidence not worth claiming", + "addr", address, + "sbh", evidence.SessionBlockHeight, + "chain", evidence.Chain, + "proofs", evidence.NumOfProofs, + "rewardExpected", rewardExpected, + "rewardCost", rewardCost, + ) + if err := pc.DeleteEvidence( + evidence.SessionHeader, + evidenceType, + node.EvidenceStore, + ); err != nil { + ctx.Logger().Debug(err.Error()) + } + continue + } + } if ctx.BlockHeight() <= evidence.SessionBlockHeight+k.BlocksPerSession(sessionCtx)-1 { // ensure session is over ctx.Logger().Info("the session is ongoing, so will not send the claim-tx yet") continue diff --git a/x/pocketcore/types/expectedKeepers.go b/x/pocketcore/types/expectedKeepers.go index ab82056c5..ce6c17225 100644 --- a/x/pocketcore/types/expectedKeepers.go +++ b/x/pocketcore/types/expectedKeepers.go @@ -9,6 +9,11 @@ import ( ) type PosKeeper interface { + CalculateRelayReward( + ctx sdk.Ctx, chain string, + relays sdk.BigInt, + stake sdk.BigInt, + ) (nodeReward, feesCollected sdk.BigInt) RewardForRelays(ctx sdk.Ctx, relays sdk.BigInt, address sdk.Address) sdk.BigInt RewardForRelaysPerChain( ctx sdk.Ctx, @@ -27,6 +32,7 @@ type PosKeeper interface { StakeDenom(ctx sdk.Ctx) (res string) GetValidatorsByChain(ctx sdk.Ctx, networkID string) (validators []sdk.Address, total int) MaxChains(ctx sdk.Ctx) (maxChains int64) + GetRewardCost(ctx sdk.Ctx) sdk.BigInt } type AppsKeeper interface { diff --git a/x/pocketcore/types/service_test.go b/x/pocketcore/types/service_test.go index 79d7950e6..a03d6d1e2 100644 --- a/x/pocketcore/types/service_test.go +++ b/x/pocketcore/types/service_test.go @@ -353,6 +353,19 @@ func (m MockPosKeeper) GetValidatorsByChain(ctx sdk.Ctx, networkID string) (vali return } +func (m MockPosKeeper) CalculateRelayReward( + ctx sdk.Ctx, + chain string, + relays sdk.BigInt, + stake sdk.BigInt, +) (sdk.BigInt, sdk.BigInt) { + panic("implement me") +} + +func (m MockPosKeeper) GetRewardCost(ctx sdk.Ctx) sdk.BigInt { + panic("implement me") +} + func (m MockPosKeeper) RewardForRelays(ctx sdk.Ctx, relays sdk.BigInt, address sdk.Address) sdk.BigInt { panic("implement me") }