Skip to content

Commit

Permalink
address comments
Browse files Browse the repository at this point in the history
  • Loading branch information
msmania committed Dec 22, 2023
1 parent f25219f commit 64f0097
Show file tree
Hide file tree
Showing 27 changed files with 762 additions and 1,248 deletions.
21 changes: 18 additions & 3 deletions app/cmd/cli/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ Will prompt the user for the <fromAddr> account passphrase.`,
},
}

// stakeNewCmd is an upgraded version of `nodesCmd` that captures newer
// on-chain functionality in a cleaner way
var stakeNewCmd = &cobra.Command{
Use: `stakeNew <OperatorPublicKey> <OutputAddress> <SignerAddress> <Stake> <ChainIDs> <ServiceURL> <Delegators> <NetworkID> <Fee> [Memo]`,
Use: "stakeNew <OperatorPublicKey> <OutputAddress> <SignerAddress> <Stake> <ChainIDs> <ServiceURL> <RewardDelegators> <NetworkID> <Fee> [Memo]",
Short: "Stake a node in the network",
Long: `Stake a node in the network, promoting it to a servicer or a validator.
Expand All @@ -131,10 +133,23 @@ The command takes the following parameters.
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.
Delegators Delegator addresses to share rewards
RewardDelegators Addresses to share rewards
NetworkID Network ID to submit a transaction to e.g. mainnet or testnet
Fee Transaction fee in uPOKT
Memo Text to include in the transaction. No functional effect.
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) {
Expand Down
2 changes: 1 addition & 1 deletion app/cmd/cli/txUtil.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func BuildStakeTx(
}

if len(delegatorsStr) > 0 {
if json.Unmarshal([]byte(delegatorsStr), &msg.Delegators); err != nil {
if json.Unmarshal([]byte(delegatorsStr), &msg.RewardDelegators); err != nil {
return nil, err
}
}
Expand Down
73 changes: 61 additions & 12 deletions app/cmd/rpc/rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1471,7 +1471,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 ""
Expand All @@ -1491,7 +1491,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())
}
Expand Down Expand Up @@ -1635,8 +1635,52 @@ 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) {
// Tx 3640B15041998FE800C2F61FC033CBF295D9282B5E7045A16F754ED9D8A54AFF in Mainnet
// 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"}' \
// <Pocket Mainnet Endpoint>/v1/query/tx | jq '.tx'
StakeTxBeforeDelegatorsUpgrade :=
"/wIK4QEKFy94Lm5vZGVzLk1zZ1Byb3RvU3Rha2U4EsUBCiBzfNC5BqUX6Aow9768" +
"QTKyYiRdhqrGqeqTIMVSckAe8RIEMDAwMxIEMDAwNBIEMDAwNRIEMDAwORIEMDAy" +
Expand All @@ -1647,16 +1691,19 @@ func TestMsgStake_Marshaling_BackwardCompatibility(t *testing.T) {
"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 :=
"5wIK3gEKFy94Lm5vZGVzLk1zZ1Byb3RvU3Rha2U4EsIBCiDiN+/FSpPtYWiZWemv" +
"oNS9SfoRwLlGw15r66zLBSzj/BIEMDAwMRIEQkVFRhoNODAwMDAwMDAwMDAwMCIR" +
"3wIK3gEKFy94Lm5vZGVzLk1zZ1Byb3RvU3Rha2U4EsIBCiDiN+/FSpPtYWiZWemv" +
"oNS9SfoRwLlGw15r66zLBSzj/BIEREVBRBIEQkVFRhoNODAwMDAwMDAwMDAwMCIR" +
"aHR0cHM6Ly94LmNvbTo0NDMqFP6BhSfNdDhmwdtr3rGHMdBIkd94MiwKKDIwMDAw" +
"MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAQAjIsCigxMDAwMDAw" +
"MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwEAESDgoFdXBva3QSBTEw" +
"MDAwGmQKICMRMWDdwHGZU6kMUecdxLF6UgHw0L1Vcc8lzz8Ynz0ZEkA+A9PANYsP" +
"+z7TduPuM7iM6jRILBJsdz0OMiGFrpGgJAsw7YrzXloJE4hyI921HoQ/bRFdw3/N" +
"Nea33C6VZqUGIgRtZW1vKKCQ7dyJ3LatFw=="
"MDAwGmQKIOI378VKk+1haJlZ6a+g1L1J+hHAuUbDXmvrrMsFLOP8EkDKz4AcELVB" +
"8Lyzi0+MVD/KXDIlTqjNLlBvFzOen7kZpR1it6gD79SLJXfWhB0qeu7Bux2VWQyf" +
"2wBBckGpIesBIgRtZW1vKCo="

originalNCUST := codec.UpgradeFeatureMap[codec.NonCustodialUpdateKey]
t.Cleanup(func() {
Expand All @@ -1670,17 +1717,19 @@ func TestMsgStake_Marshaling_BackwardCompatibility(t *testing.T) {
// 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.Delegators)
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.Delegators)
assert.NotNil(t, msgStake.RewardDelegators)
assert.Nil(t, msgStake.ValidateBasic())
}
8 changes: 4 additions & 4 deletions codec/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const (
ClearUnjailedValSessionKey = "CRVAL"
PerChainRTTM = "PerChainRTTM"
AppTransferKey = "AppTransfer"
RewardsDelegatorKey = "RewardDelegator"
RewardDelegatorsKey = "RewardDelegators"
)

func GetCodecUpgradeHeight() int64 {
Expand Down Expand Up @@ -295,9 +295,9 @@ func (cdc *Codec) IsAfterAppTransferUpgrade(height int64) bool {
TestMode <= -3
}

func (cdc *Codec) IsAfterDelegatorUpgrade(height int64) bool {
return (UpgradeFeatureMap[RewardsDelegatorKey] != 0 &&
height >= UpgradeFeatureMap[RewardsDelegatorKey]) ||
func (cdc *Codec) IsAfterRewardDelegatorUpgrade(height int64) bool {
return (UpgradeFeatureMap[RewardDelegatorsKey] != 0 &&
height >= UpgradeFeatureMap[RewardDelegatorsKey]) ||
TestMode <= -3
}

Expand Down
7 changes: 4 additions & 3 deletions proto/x/nodes/msg.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ message MsgProtoStake {
(gogoproto.jsontag) = "output_address,omitempty",
(gogoproto.moretags) = "yaml:\"output_address\""
];
map<string, uint32> Delegators = 6 [
(gogoproto.jsontag) = "delegators,omitempty",
(gogoproto.moretags) = "yaml:\"delegators\""
// Mapping from delegated-to addresses to a percentage of rewards.
map<string, uint32> RewardDelegators = 6 [
(gogoproto.jsontag) = "reward_delegators,omitempty",
(gogoproto.moretags) = "yaml:\"reward_delegators\""
];
}

Expand Down
18 changes: 1 addition & 17 deletions proto/x/nodes/nodes.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +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<string, uint32> Delegators = 10 [(gogoproto.jsontag) = "delegators,omitempty", (gogoproto.moretags) = "yaml:\"delegators\""];
}

message ProtoValidatorV8 {
option (gogoproto.equal) = true;
option (gogoproto.goproto_stringer) = true;
option (gogoproto.goproto_getters) = false;

bytes Address = 1 [(gogoproto.casttype) = "github.com/pokt-network/pocket-core/types.Address", (gogoproto.moretags) = "yaml:\"address\"", (gogoproto.jsontag) = "address"];
bytes PublicKey = 2 [(gogoproto.moretags) = "yaml:\"public_key\"", (gogoproto.jsontag) = "public_key"];
bool jailed = 3 [(gogoproto.jsontag) = "jailed"];
int32 status = 4 [(gogoproto.jsontag) = "status"];
repeated string Chains = 5 [(gogoproto.jsontag) = "chains"];
string ServiceURL = 6 [(gogoproto.jsontag) = "service_url"];
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<string, uint32> RewardDelegators = 10 [(gogoproto.jsontag) = "reward_delegators,omitempty", (gogoproto.moretags) = "yaml:\"reward_delegators\""];
}

message LegacyProtoValidator {
Expand Down
64 changes: 32 additions & 32 deletions types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,38 @@ type SDKConfig struct {
}

type PocketConfig struct {
DataDir string `json:"data_dir"`
GenesisName string `json:"genesis_file"`
ChainsName string `json:"chains_name"`
EvidenceDBName string `json:"evidence_db_name"`
TendermintURI string `json:"tendermint_uri"`
KeybaseName string `json:"keybase_name"`
RPCPort string `json:"rpc_port"`
ClientBlockSyncAllowance int `json:"client_block_sync_allowance"`
ClientSessionSyncAllowance int64 `json:"client_session_sync_allowance"`
MaxEvidenceCacheEntires int `json:"max_evidence_cache_entries"`
MaxSessionCacheEntries int `json:"max_session_cache_entries"`
JSONSortRelayResponses bool `json:"json_sort_relay_responses"`
RemoteCLIURL string `json:"remote_cli_url"`
UserAgent string `json:"user_agent"`
ValidatorCacheSize int64 `json:"validator_cache_size"`
ApplicationCacheSize int64 `json:"application_cache_size"`
RPCTimeout int64 `json:"rpc_timeout"`
PrometheusAddr string `json:"pocket_prometheus_port"`
PrometheusMaxOpenfiles int `json:"prometheus_max_open_files"`
MaxClaimAgeForProofRetry int `json:"max_claim_age_for_proof_retry"`
ProofPrevalidation bool `json:"proof_prevalidation"`
CtxCacheSize int `json:"ctx_cache_size"`
ABCILogging bool `json:"abci_logging"`
RelayErrors bool `json:"show_relay_errors"`
DisableTxEvents bool `json:"disable_tx_events"`
Cache bool `json:"-"`
IavlCacheSize int64 `json:"iavl_cache_size"`
ChainsHotReload bool `json:"chains_hot_reload"`
GenerateTokenOnStart bool `json:"generate_token_on_start"`
LeanPocket bool `json:"lean_pocket"`
LeanPocketUserKeyFileName string `json:"lean_pocket_user_key_file"`
NotClaimPossiblyNegativeRewards bool `json:"not_claim_possibly_negative_rewards"`
DataDir string `json:"data_dir"`
GenesisName string `json:"genesis_file"`
ChainsName string `json:"chains_name"`
EvidenceDBName string `json:"evidence_db_name"`
TendermintURI string `json:"tendermint_uri"`
KeybaseName string `json:"keybase_name"`
RPCPort string `json:"rpc_port"`
ClientBlockSyncAllowance int `json:"client_block_sync_allowance"`
ClientSessionSyncAllowance int64 `json:"client_session_sync_allowance"`
MaxEvidenceCacheEntires int `json:"max_evidence_cache_entries"`
MaxSessionCacheEntries int `json:"max_session_cache_entries"`
JSONSortRelayResponses bool `json:"json_sort_relay_responses"`
RemoteCLIURL string `json:"remote_cli_url"`
UserAgent string `json:"user_agent"`
ValidatorCacheSize int64 `json:"validator_cache_size"`
ApplicationCacheSize int64 `json:"application_cache_size"`
RPCTimeout int64 `json:"rpc_timeout"`
PrometheusAddr string `json:"pocket_prometheus_port"`
PrometheusMaxOpenfiles int `json:"prometheus_max_open_files"`
MaxClaimAgeForProofRetry int `json:"max_claim_age_for_proof_retry"`
ProofPrevalidation bool `json:"proof_prevalidation"`
CtxCacheSize int `json:"ctx_cache_size"`
ABCILogging bool `json:"abci_logging"`
RelayErrors bool `json:"show_relay_errors"`
DisableTxEvents bool `json:"disable_tx_events"`
Cache bool `json:"-"`
IavlCacheSize int64 `json:"iavl_cache_size"`
ChainsHotReload bool `json:"chains_hot_reload"`
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 {
Expand Down
29 changes: 27 additions & 2 deletions x/auth/types/txbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down
15 changes: 11 additions & 4 deletions x/nodes/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,20 @@ func handleStake(ctx sdk.Ctx, msg types.MsgStake, k keeper.Keeper, signer crypto
}
}

if !k.Cdc.IsAfterDelegatorUpgrade(ctx.BlockHeight()) &&
msg.Delegators != nil {
msg.Delegators = nil
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)
// StakedTokens is set through StakeValidator. Resetting to 0 for now.
// 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 {
Expand Down
Loading

0 comments on commit 64f0097

Please sign in to comment.