Skip to content

Commit

Permalink
[Morse->Shannon Migration] Scaffold MorseClaimableAccount (#1068)
Browse files Browse the repository at this point in the history
## Summary

Scaffold a new on-chain (persisted) map that will track the claimable
accounts from Morse. We want to store counts as normalized entities such
that we can leverage conventional data access paradigms (as opposed to
dumping a blob of Morse state on Shannon).

```bash
ignite scaffold map morse_claimable_account --no-message --module migration --index address public_key unstaked_balance:coin supplier_stake:coin application_stake:coin claimed_at_height:int64
```

Changes:
- Scaffold `MorseClaimableAccount`
- Update types & fix tests
- Refactor `poktrolld migrate collect-morse-accounts` to track balances
and stakes independently

## Issue

- Issue: #1034

## Type of change

Select one or more from the following:

- [x] New feature, functionality or library
- [ ] Consensus breaking; add the `consensus-breaking` label if so. See
#791 for details
- [ ] Bug fix
- [ ] Code health or cleanup
- [ ] Documentation
- [ ] Other (specify)

## Sanity Checklist

- [x] I have updated the GitHub Issue `assignees`, `reviewers`,
`labels`, `project`, `iteration` and `milestone`
- [ ] For docs, I have run `make docusaurus_start`
- [x] For code, I have run `make go_develop_and_test` and `make
test_e2e`
- [x] For code, I have added the `devnet-test-e2e` label to run E2E
tests in CI
- [ ] For configurations, I have update the documentation
- [x] I added TODOs where applicable

---------

Co-authored-by: Daniel Olshansky <[email protected]>
  • Loading branch information
bryanchriswhite and Olshansk authored Feb 14, 2025
1 parent e2f3c84 commit 851dea5
Show file tree
Hide file tree
Showing 30 changed files with 6,653 additions and 1,815 deletions.
214 changes: 186 additions & 28 deletions api/poktroll/migration/genesis.pulsar.go

Large diffs are not rendered by default.

1,456 changes: 1,334 additions & 122 deletions api/poktroll/migration/morse_offchain.pulsar.go

Large diffs are not rendered by default.

1,459 changes: 425 additions & 1,034 deletions api/poktroll/migration/morse_onchain.pulsar.go

Large diffs are not rendered by default.

2,224 changes: 2,181 additions & 43 deletions api/poktroll/migration/query.pulsar.go

Large diffs are not rendered by default.

80 changes: 79 additions & 1 deletion api/poktroll/migration/query_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions cmd/poktrolld/cmd/migrate/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func collectInputAccountBalances(inputState *migrationtypes.MorseStateExport, mo
return ErrMorseExportState.Wrapf("unsupported denom %q", coin.Denom)
}

if err := morseWorkspace.addUpokt(accountAddr, coin.Amount); err != nil {
if err := morseWorkspace.addUnstakedBalance(accountAddr, coin.Amount); err != nil {
return fmt.Errorf(
"adding morse account balance (%s) to account balance of address %q: %w",
coin, accountAddr, err,
Expand Down Expand Up @@ -265,7 +265,7 @@ func collectInputApplicationStakes(inputState *migrationtypes.MorseStateExport,
return ErrMorseExportState.Wrapf("failed to parse application stake amount %q", exportApplication.StakedTokens)
}

if err := morseWorkspace.addUpokt(appAddr, appStakeAmtUpokt); err != nil {
if err := morseWorkspace.addAppStake(appAddr, appStakeAmtUpokt); err != nil {
return fmt.Errorf(
"adding application stake amount to account balance of address %q: %w",
appAddr, err,
Expand Down Expand Up @@ -304,7 +304,7 @@ func collectInputSupplierStakes(inputState *migrationtypes.MorseStateExport, mor
return ErrMorseExportState.Wrapf("failed to parse supplier stake amount %q", exportSupplier.StakedTokens)
}

if err := morseWorkspace.addUpokt(supplierAddr, supplierStakeAmtUpokt); err != nil {
if err := morseWorkspace.addSupplierStake(supplierAddr, supplierStakeAmtUpokt); err != nil {
return fmt.Errorf(
"adding supplier stake amount to account balance of address %q: %w",
supplierAddr, err,
Expand Down
34 changes: 17 additions & 17 deletions cmd/poktrolld/cmd/migrate/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,13 @@ func TestNewTestMorseStateExport(t *testing.T) {
numTotalAccounts += k
}

expectedShannonAccountBalance := fmt.Sprintf("%d%d%d0%d%d%d", i, i, i, i, i, i)
// i=1 -> "100000001", i=2 -> "200000002": creates scaled balance with unique ID
expectedShannonAccountBalance := fmt.Sprintf("%d00000%d", i, i)

// n=5 -> "5000050": scales with total accounts plus unique suffix
expectedShannonTotalAppStake := fmt.Sprintf("%d000%d0", numTotalAccounts, numTotalAccounts)

// n=5 -> "505000": different scaling pattern using same total accounts
expectedShannonTotalSupplierStake := fmt.Sprintf("%d0%d00", numTotalAccounts, numTotalAccounts)

morseWorkspace := newMorseImportWorkspace()
Expand All @@ -96,7 +101,7 @@ func TestNewTestMorseStateExport(t *testing.T) {
require.Equal(t, uint64(i), morseWorkspace.numSuppliers)

morseAccounts := morseWorkspace.accountState.Accounts[i-1]
require.Equal(t, expectedShannonAccountBalance, morseAccounts.Coins[0].Amount.String())
require.Equal(t, expectedShannonAccountBalance, morseAccounts.UnstakedBalance.Amount.String())
require.Equal(t, expectedShannonTotalAppStake, morseWorkspace.accumulatedTotalAppStake.String())
require.Equal(t, expectedShannonTotalSupplierStake, morseWorkspace.accumulatedTotalSupplierStake.String())
})
Expand Down Expand Up @@ -139,8 +144,7 @@ func newMorseStateExportAndAccountState(
}

morseAccountState := &migrationtypes.MorseAccountState{
AccountsIdxByAddress: make(map[string]uint64),
Accounts: make([]*migrationtypes.MorseAccount, numAccounts),
Accounts: make([]*migrationtypes.MorseClaimableAccount, numAccounts),
}

for i := 1; i < numAccounts+1; i++ {
Expand All @@ -149,10 +153,9 @@ func newMorseStateExportAndAccountState(
binary.LittleEndian.PutUint64(seedBz, seedUint)
privKey := cometcrypto.GenPrivKeyFromSecret(seedBz)
pubKey := privKey.PubKey()
balanceAmount := int64(1e6*i + i) // i_000_00i
appStakeAmount := int64(1e5*i + (i * 10)) // i00_0i0
supplierStakeAmount := int64(1e4*i + (i * 100)) // i0_i00
sumAmount := balanceAmount + appStakeAmount + supplierStakeAmount // i_ii0_iii
balanceAmount := int64(1e6*i + i) // i_000_00i
appStakeAmount := int64(1e5*i + (i * 10)) // i00_0i0
supplierStakeAmount := int64(1e4*i + (i * 100)) // i0_i00

// Add an account.
morseStateExport.AppState.Auth.Accounts = append(
Expand Down Expand Up @@ -194,16 +197,13 @@ func newMorseStateExportAndAccountState(
)

// Add the account to the morseAccountState.
morseAccountState.Accounts[i-1] = &migrationtypes.MorseAccount{
Address: pubKey.Address(),
Coins: cosmostypes.NewCoins(cosmostypes.NewInt64Coin(volatile.DenomuPOKT, sumAmount)),
PubKey: &migrationtypes.MorsePublicKey{
Value: pubKey.Bytes(),
},
morseAccountState.Accounts[i-1] = &migrationtypes.MorseClaimableAccount{
Address: pubKey.Address(),
UnstakedBalance: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, balanceAmount),
SupplierStake: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, supplierStakeAmount),
ApplicationStake: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, appStakeAmount),
PublicKey: pubKey.Bytes(),
}

// Add the account index to the morseAccountState.
morseAccountState.AccountsIdxByAddress[pubKey.Address().String()] = uint64(i - 1)
}

var err error
Expand Down
85 changes: 49 additions & 36 deletions cmd/poktrolld/cmd/migrate/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
// newMorseImportWorkspace returns a new morseImportWorkspace with fields initialized to their zero values.
func newMorseImportWorkspace() *morseImportWorkspace {
return &morseImportWorkspace{
accountIdxByAddress: make(map[string]uint64),
accountState: &migrationtypes.MorseAccountState{
AccountsIdxByAddress: make(map[string]uint64),
Accounts: make([]*migrationtypes.MorseAccount, 0),
Accounts: make([]*migrationtypes.MorseClaimableAccount, 0),
},
accumulatedTotalBalance: cosmosmath.ZeroInt(),
accumulatedTotalAppStake: cosmosmath.ZeroInt(),
Expand All @@ -26,6 +26,9 @@ func newMorseImportWorkspace() *morseImportWorkspace {
// morseImportWorkspace is a helper struct that is used to consolidate the Morse account balance,
// application stake, and supplier stake for each account as an entry in the resulting MorseAccountState.
type morseImportWorkspace struct {
// accountIdxByAddress is a map from the hex-encoded Morse address to the index
// of the corresponding MorseAccount in the accounts slice.
accountIdxByAddress map[string]uint64
// accountState is the final MorseAccountState that will be imported into Shannon.
// It includes a slice of MorseAccount objects which are populated, by transforming
// the input MorseStateExport into the output MorseAccountState.
Expand Down Expand Up @@ -54,23 +57,23 @@ func (miw *morseImportWorkspace) nextIdx() int64 {
// getAccount returns the MorseAccount for the given address and its index,
// if present, in the accountState accounts slice.
// If the given address is not present, it returns nil, -1.
func (miw *morseImportWorkspace) getAccount(addr string) (*migrationtypes.MorseAccount, int64) {
accountIdx, ok := miw.accountState.AccountsIdxByAddress[addr]
func (miw *morseImportWorkspace) getAccount(morseAddress string) (*migrationtypes.MorseClaimableAccount, error) {
accountIdx, ok := miw.accountIdxByAddress[morseAddress]
if !ok {
return nil, -1
return nil, ErrMorseStateTransform.Wrapf("account %q not found", morseAddress)
}

account := miw.accountState.GetAccounts()[accountIdx]
return account, int64(accountIdx)
return account, nil
}

// hasAccount returns true if the given address is present in the accounts slice.
func (miw *morseImportWorkspace) hasAccount(addr string) bool {
_, accountIdx := miw.getAccount(addr)
return accountIdx != -1
func (miw *morseImportWorkspace) hasAccount(morseAddress string) bool {
_, err := miw.getAccount(morseAddress)
return err == nil
}

// getNumAccounts returns the number of accounts in the accountState accounts map.
// getNumAccounts returns the number of Morse accounts in the accountState accounts map.
func (miw *morseImportWorkspace) getNumAccounts() uint64 {
return uint64(len(miw.accountState.GetAccounts()))
}
Expand Down Expand Up @@ -103,56 +106,66 @@ func (miw *morseImportWorkspace) accumulatedTotalsSum() cosmosmath.Int {
Add(miw.accumulatedTotalSupplierStake)
}

// addAccount adds the account with the given address to the accounts slice and
// its corresponding address is in the addressToIdx map.
// addAccount adds the Morse account with the given Morse address to the accounts
// slice and its corresponding address is in the accountIdxByAddress map.
// If the address is already present, an error is returned.
func (miw *morseImportWorkspace) addAccount(
addr string,
exportAccount *migrationtypes.MorseAuthAccount,
) (accountIdx int64, balance cosmostypes.Coin, err error) {
// Initialize balance to zero
// Initialize balance to zero.
// DEV_NOTE: This guarantees that all accounts tracked by the morseWorkspace have the upokt denom.
balance = cosmostypes.NewCoin(volatile.DenomuPOKT, cosmosmath.ZeroInt())

if _, accountIdx = miw.getAccount(addr); accountIdx != -1 {
if _, err = miw.getAccount(addr); err == nil {
return 0, cosmostypes.Coin{}, ErrMorseStateTransform.Wrapf(
"unexpected workspace state: account already exists (%s)", addr,
)
}

accountIdx = miw.nextIdx()
importAccount := &migrationtypes.MorseAccount{
Address: exportAccount.Value.Address,
PubKey: exportAccount.Value.PubKey,
Coins: cosmostypes.Coins{balance},
importAccount := &migrationtypes.MorseClaimableAccount{
Address: exportAccount.Value.Address,
PublicKey: exportAccount.Value.PubKey.Value,
UnstakedBalance: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0),
SupplierStake: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0),
ApplicationStake: cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0),
}
miw.accountState.Accounts = append(miw.accountState.Accounts, importAccount)
miw.accountState.AccountsIdxByAddress[addr] = uint64(accountIdx)
miw.accountIdxByAddress[addr] = uint64(accountIdx)

return accountIdx, balance, nil
}

// addUpokt adds the given amount to the corresponding account balances in the morseWorkspace.
func (miw *morseImportWorkspace) addUpokt(addr string, amount cosmosmath.Int) error {
account, accountIdx := miw.getAccount(addr)
if accountIdx == -1 {
return ErrMorseStateTransform.Wrapf("account %q not found", addr)
// addUnstakedBalance adds the given amount to the corresponding Morse account balances in the morseWorkspace.
func (miw *morseImportWorkspace) addUnstakedBalance(addr string, amount cosmosmath.Int) error {
account, err := miw.getAccount(addr)
if err != nil {
return err
}

if len(account.Coins) != 1 {
return ErrMorseStateTransform.Wrapf(
"account %q has %d token denominations, expected upokt only: %s",
addr, len(account.Coins), account.Coins,
)
account.UnstakedBalance.Amount = account.UnstakedBalance.Amount.Add(amount)
return nil
}

// addSupplierStake adds the given amount to the corresponding Morse account balances in the morseWorkspace.
func (miw *morseImportWorkspace) addSupplierStake(addr string, amount cosmosmath.Int) error {
account, err := miw.getAccount(addr)
if err != nil {
return err
}

upoktCoins := account.Coins[0]
if upoktCoins.Denom != volatile.DenomuPOKT {
return fmt.Errorf(
"account %q has %s token denomination, expected upokt only: %s",
addr, upoktCoins.Denom, account.Coins,
)
account.SupplierStake.Amount = account.SupplierStake.Amount.Add(amount)
return nil
}

// addAppStake adds the given amount to the corresponding Morse account balances in the morseWorkspace.
func (miw *morseImportWorkspace) addAppStake(addr string, amount cosmosmath.Int) error {
account, err := miw.getAccount(addr)
if err != nil {
return err
}

account.Coins[0].Amount = account.Coins[0].Amount.Add(amount)
account.ApplicationStake.Amount = account.ApplicationStake.Amount.Add(amount)
return nil
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ go 1.23.0
// github.com/pokt-network/smt/kvstore/pebble => ../smt/kvstore/pebble
// )

replace nhooyr.io/websocket => github.com/coder/websocket v1.8.6

// replace broken goleveldb
replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7

Expand Down
Loading

0 comments on commit 851dea5

Please sign in to comment.