Skip to content

Commit

Permalink
Address PR comments
Browse files Browse the repository at this point in the history
  • Loading branch information
jerryfan01234 committed Jul 23, 2024
1 parent 952dfdc commit a6ae93c
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 366 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import { DeepPartial } from "../../helpers";
/** Module genesis state */

export interface GenesisState {
/** Module genesis state */
accounts: AccountState[];
}
/** Module genesis state */

export interface GenesisStateSDKType {
/** Module genesis state */
accounts: AccountStateSDKType[];
}

Expand Down
5 changes: 4 additions & 1 deletion proto/dydxprotocol/accountplus/accountplus.proto
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
syntax = "proto3";
package dydxprotocol.accountplus;

import "gogoproto/gogo.proto";

option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types";

// Account State
message AccountState {
string address = 1;
TimestampNonceDetails timestamp_nonce_details = 2;
TimestampNonceDetails timestamp_nonce_details = 2
[ (gogoproto.nullable) = false ];
}

// Timestamp nonce details
Expand Down
5 changes: 4 additions & 1 deletion proto/dydxprotocol/accountplus/genesis.proto
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
syntax = "proto3";
package dydxprotocol.accountplus;

import "gogoproto/gogo.proto";
import "dydxprotocol/accountplus/accountplus.proto";

option go_package = "github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types";

// Module genesis state
message GenesisState { repeated AccountState accounts = 1; }
message GenesisState {
repeated AccountState accounts = 1 [ (gogoproto.nullable) = false ];
}
6 changes: 5 additions & 1 deletion protocol/x/accountplus/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, data types.GenesisState) {
}

func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
accounts, err := k.GetAllAccountStates(ctx)
if err != nil {
panic(err)
}
return &types.GenesisState{
Accounts: k.GetAllAccountStates(ctx),
Accounts: accounts,
}
}
61 changes: 22 additions & 39 deletions protocol/x/accountplus/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ import (
"math"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
testapp "github.com/dydxprotocol/v4-chain/protocol/testutil/app"
"github.com/dydxprotocol/v4-chain/protocol/testutil/constants"
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus"
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus/keeper"
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus/testutils"
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types"
"github.com/stretchr/testify/require"
)
Expand All @@ -20,53 +17,53 @@ func TestImportExportGenesis(t *testing.T) {
genesisState *types.GenesisState
// The order of this list may not match the order in GenesisState. We want our tests to be deterministic so
// order of expectedAccountStates was manually set based on test debug. This ordering should only be changed if
// additional accounts added to genesisState. If a feature breaks the existing ordering, should look into ßwhy.
expectedAccountStates []*types.AccountState
// additional accounts added to genesisState. If a feature breaks the existing ordering, should look into why.
expectedAccountStates []types.AccountState
}{
"non-empty genesis": {
genesisState: &types.GenesisState{
Accounts: []*types.AccountState{
Accounts: []types.AccountState{
{
Address: constants.AliceAccAddress.String(),
TimestampNonceDetails: &types.TimestampNonceDetails{
TimestampNonceDetails: types.TimestampNonceDetails{
TimestampNonces: []uint64{baseTsNonce + 1, baseTsNonce + 2, baseTsNonce + 3},
MaxEjectedNonce: baseTsNonce,
},
},
{
Address: constants.BobAccAddress.String(),
TimestampNonceDetails: &types.TimestampNonceDetails{
TimestampNonceDetails: types.TimestampNonceDetails{
TimestampNonces: []uint64{baseTsNonce + 5, baseTsNonce + 6, baseTsNonce + 7},
MaxEjectedNonce: baseTsNonce + 1,
},
},
{
Address: constants.CarlAccAddress.String(),
TimestampNonceDetails: &types.TimestampNonceDetails{
TimestampNonceDetails: types.TimestampNonceDetails{
TimestampNonces: []uint64{baseTsNonce + 5, baseTsNonce + 6, baseTsNonce + 7},
MaxEjectedNonce: baseTsNonce + 1,
},
},
},
},
expectedAccountStates: []*types.AccountState{
expectedAccountStates: []types.AccountState{
{
Address: constants.AliceAccAddress.String(),
TimestampNonceDetails: &types.TimestampNonceDetails{
TimestampNonceDetails: types.TimestampNonceDetails{
TimestampNonces: []uint64{baseTsNonce + 1, baseTsNonce + 2, baseTsNonce + 3},
MaxEjectedNonce: baseTsNonce,
},
},
{
Address: constants.CarlAccAddress.String(),
TimestampNonceDetails: &types.TimestampNonceDetails{
TimestampNonceDetails: types.TimestampNonceDetails{
TimestampNonces: []uint64{baseTsNonce + 5, baseTsNonce + 6, baseTsNonce + 7},
MaxEjectedNonce: baseTsNonce + 1,
},
},
{
Address: constants.BobAccAddress.String(),
TimestampNonceDetails: &types.TimestampNonceDetails{
TimestampNonceDetails: types.TimestampNonceDetails{
TimestampNonces: []uint64{baseTsNonce + 5, baseTsNonce + 6, baseTsNonce + 7},
MaxEjectedNonce: baseTsNonce + 1,
},
Expand All @@ -75,9 +72,9 @@ func TestImportExportGenesis(t *testing.T) {
},
"empty genesis": {
genesisState: &types.GenesisState{
Accounts: []*types.AccountState{},
Accounts: []types.AccountState{},
},
expectedAccountStates: []*types.AccountState{},
expectedAccountStates: []types.AccountState{},
},
}

Expand All @@ -87,38 +84,24 @@ func TestImportExportGenesis(t *testing.T) {
ctx := tApp.InitChain()
k := tApp.App.AccountPlusKeeper

// Initialize genesis state
accountplus.InitGenesis(ctx, k, *tc.genesisState)

// Check that keeper state is correct
compareKeeperWithGenesisState(t, ctx, &k, tc.expectedAccountStates)
// Check that keeper accounts states are correct
actualAccountStates, _ := k.GetAllAccountStates(ctx)
require.Equal(
t,
tc.expectedAccountStates,
actualAccountStates,
"Keeper account states do not match Genesis account states",
)

// Export the genesis state
exportedGenesis := accountplus.ExportGenesis(ctx, k)

// Ensure the exported state matches the expected state
// Check that the exported state matches the expected state
expectedGenesis := &types.GenesisState{
Accounts: tc.expectedAccountStates,
}
requireGenesisStatesEqual(t, exportedGenesis, expectedGenesis)
require.Equal(t, *exportedGenesis, *expectedGenesis)
})
}
}

func compareKeeperWithGenesisState(
t *testing.T,
ctx sdk.Context,
k *keeper.Keeper,
expectedAccountStates []*types.AccountState,
) {
// Compare states. Order matters.
isEqual := testutils.CompareAccountStateLists(k.GetAllAccountStates(ctx), expectedAccountStates)

require.True(t, isEqual, "Keeper account states does not match Genesis account states")
}

func requireGenesisStatesEqual(t *testing.T, actualGenesisState, expectedGenesisState *types.GenesisState) {
isEqual := testutils.CompareAccountStateLists(actualGenesisState.GetAccounts(), expectedGenesisState.GetAccounts())

require.True(t, isEqual, "GenesisState mismatch")
}
59 changes: 35 additions & 24 deletions protocol/x/accountplus/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ import (
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types"
)

func DefaultAccountState(address sdk.AccAddress) types.AccountState {
return types.AccountState{
Address: address.String(),
TimestampNonceDetails: types.TimestampNonceDetails{
MaxEjectedNonce: 0,
TimestampNonces: []uint64{},
},
}
}

type Keeper struct {
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
Expand All @@ -32,77 +42,78 @@ func (k Keeper) InitializeForGenesis(ctx sdk.Context) {
}

// Get all account details pairs in store
func (k Keeper) GetAllAccountStates(ctx sdk.Context) []*types.AccountState {
func (k Keeper) GetAllAccountStates(ctx sdk.Context) ([]types.AccountState, error) {
store := ctx.KVStore(k.storeKey)

iterator := storetypes.KVStorePrefixIterator(store, nil)
defer iterator.Close()

var accounts []*types.AccountState
accounts := []types.AccountState{}
for ; iterator.Valid(); iterator.Next() {
var account types.AccountState
k.cdc.MustUnmarshal(iterator.Value(), &account)
accounts = append(accounts, &account)
accountState, found := k.GetAccountState(ctx, iterator.Key())
if !found {
return accounts, errors.New("Could not get account state for address: " + sdk.AccAddress(iterator.Key()).String())
}
accounts = append(accounts, accountState)
}

return accounts
return accounts, nil
}

// Set genesis state
func (k Keeper) SetGenesisState(ctx sdk.Context, data types.GenesisState) error {
store := ctx.KVStore(k.storeKey)

for _, account := range data.Accounts {
address, err := sdk.AccAddressFromBech32(account.Address)
if err != nil {
return err
}
k.setAccountState(store, address, *account)
k.setAccountState(ctx, address, account)
}

return nil
}

func (k Keeper) InitializeAccount(ctx sdk.Context, address sdk.AccAddress) (types.AccountState, error) {
store := ctx.KVStore(k.storeKey)

if _, found := k.getAccountState(store, address); found {
return types.AccountState{}, errors.New(
func (k Keeper) InitializeAccount(ctx sdk.Context, address sdk.AccAddress) error {
if _, found := k.GetAccountState(ctx, address); found {
return errors.New(
"Cannot initialize AccountState for address with existing AccountState, address: " + address.String(),
)
}

initialAccountState := types.AccountState{
Address: address.String(),
TimestampNonceDetails: DeepCopyTimestampNonceDetails(InitialTimestampNonceDetails),
}

k.setAccountState(store, address, initialAccountState)
k.setAccountState(ctx, address, DefaultAccountState(address))

return initialAccountState, nil
return nil
}

// Get the AccountState from KVStore for a given account address
func (k Keeper) getAccountState(
store storetypes.KVStore,
func (k Keeper) GetAccountState(
ctx sdk.Context,
address sdk.AccAddress,
) (types.AccountState, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(address.Bytes())
if bz == nil {
return types.AccountState{}, false
}

var accountState types.AccountState
k.cdc.MustUnmarshal(bz, &accountState)

// By default empty slices are Unmarshed into nil
if accountState.TimestampNonceDetails.TimestampNonces == nil {
accountState.TimestampNonceDetails.TimestampNonces = make([]uint64, 0)
}

return accountState, true
}

// Set the AccountState into KVStore for a given account address
func (k Keeper) setAccountState(
store storetypes.KVStore,
ctx sdk.Context,
address sdk.AccAddress,
accountState types.AccountState,
) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&accountState)
store.Set(address.Bytes(), bz)
}
21 changes: 9 additions & 12 deletions protocol/x/accountplus/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,23 @@ import (
"github.com/dydxprotocol/v4-chain/protocol/testutil/constants"
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus"
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus/keeper"
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus/testutils"
"github.com/dydxprotocol/v4-chain/protocol/x/accountplus/types"
)

func TestInitializeAccount(t *testing.T) {
baseTsNonce := uint64(math.Pow(2, 40))
genesisState := &types.GenesisState{
Accounts: []*types.AccountState{
Accounts: []types.AccountState{
{
Address: constants.AliceAccAddress.String(),
TimestampNonceDetails: &types.TimestampNonceDetails{
TimestampNonceDetails: types.TimestampNonceDetails{
TimestampNonces: []uint64{baseTsNonce + 1, baseTsNonce + 2, baseTsNonce + 3},
MaxEjectedNonce: baseTsNonce,
},
},
{
Address: constants.BobAccAddress.String(),
TimestampNonceDetails: &types.TimestampNonceDetails{
TimestampNonceDetails: types.TimestampNonceDetails{
TimestampNonces: []uint64{baseTsNonce + 5, baseTsNonce + 6, baseTsNonce + 7},
MaxEjectedNonce: baseTsNonce + 1,
},
Expand All @@ -38,23 +37,21 @@ func TestInitializeAccount(t *testing.T) {
t.Run("Cannot initialize existing account", func(t *testing.T) {
ctx, k, _, _ := keepertest.TimestampNonceKeepers(t)
accountplus.InitGenesis(ctx, *k, *genesisState)
_, err := k.InitializeAccount(ctx, constants.AliceAccAddress)
err := k.InitializeAccount(ctx, constants.AliceAccAddress)
require.NotNil(t, err, "Account should not be able to be initialized if already exists")
})

t.Run("Can initialize new account", func(t *testing.T) {
ctx, k, _, _ := keepertest.TimestampNonceKeepers(t)
accountplus.InitGenesis(ctx, *k, *genesisState)

expectedAccount := types.AccountState{
Address: constants.CarlAccAddress.String(),
TimestampNonceDetails: keeper.DeepCopyTimestampNonceDetails(keeper.InitialTimestampNonceDetails),
}
expectedAccount := keeper.DefaultAccountState(constants.CarlAccAddress)

account, err := k.InitializeAccount(ctx, constants.CarlAccAddress)
err := k.InitializeAccount(ctx, constants.CarlAccAddress)
require.Nil(t, err, "Should be able to initialize account if it did not exist")

isAccountEqual := testutils.CompareAccountStates(&account, &expectedAccount)
require.True(t, isAccountEqual, "Initialized account does not have correct initial state")
actualAccount, found := k.GetAccountState(ctx, constants.CarlAccAddress)
require.True(t, found, "Could not find account")
require.Equal(t, actualAccount, expectedAccount)
})
}
Loading

0 comments on commit a6ae93c

Please sign in to comment.