nameservice: implement processing record and authority expiry

This commit is contained in:
nabarun 2022-04-19 12:46:24 +05:30
parent 8477b3d9cb
commit 7f70108a4a
4 changed files with 219 additions and 3 deletions

View File

@ -34,10 +34,19 @@ cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["gov"]["deposit_para
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
# Custom modules # Custom modules
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_rent"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
if [[ "$TEST_EXPIRY" == "true" ]]; then
echo "Setting timers for expiry tests."
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["record_rent_duration"]="60s"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_grace_period"]="60s"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["nameservice"]["params"]["authority_rent_duration"]="60s"' > $HOME/.chibaclonkd/config/tmp_genesis.json && mv $HOME/.chibaclonkd/config/tmp_genesis.json $HOME/.chibaclonkd/config/genesis.json
fi
if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then
echo "Enabling auction and setting timers." echo "Enabling auction and setting timers."

View File

@ -13,5 +13,8 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
// EndBlocker Called every block, update validator set // EndBlocker Called every block, update validator set
func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate { func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate {
k.ProcessRecordExpiryQueue(ctx)
k.ProcessAuthorityExpiryQueue(ctx)
return []abci.ValidatorUpdate{} return []abci.ValidatorUpdate{}
} }

View File

@ -1,6 +1,7 @@
package keeper package keeper
import ( import (
"bytes"
"fmt" "fmt"
"sort" "sort"
"time" "time"
@ -302,6 +303,102 @@ func (k Keeper) InsertRecordExpiryQueue(ctx sdk.Context, val types.Record) {
k.SetRecordExpiryQueueTimeSlice(ctx, expiryTime, timeSlice) k.SetRecordExpiryQueueTimeSlice(ctx, expiryTime, timeSlice)
} }
// DeleteRecordExpiryQueue deletes a record CID from the record expiry queue.
func (k Keeper) DeleteRecordExpiryQueue(ctx sdk.Context, record types.Record) {
expiryTime, err := time.Parse(time.RFC3339, record.ExpiryTime)
if err != nil {
panic(err)
}
timeSlice := k.GetRecordExpiryQueueTimeSlice(ctx, expiryTime)
var newTimeSlice []string
for _, cid := range timeSlice {
if !bytes.Equal([]byte(cid), []byte(record.Id)) {
newTimeSlice = append(newTimeSlice, cid)
}
}
if len(newTimeSlice) == 0 {
k.DeleteRecordExpiryQueueTimeSlice(ctx, expiryTime)
} else {
k.SetRecordExpiryQueueTimeSlice(ctx, expiryTime, newTimeSlice)
}
}
// RecordExpiryQueueIterator returns all the record expiry queue timeslices from time 0 until endTime.
func (k Keeper) RecordExpiryQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
store := ctx.KVStore(k.storeKey)
rangeEndBytes := sdk.InclusiveEndBytes(getRecordExpiryQueueTimeKey(endTime))
return store.Iterator(PrefixExpiryTimeToRecordsIndex, rangeEndBytes)
}
// GetAllExpiredRecords returns a concatenated list of all the timeslices before currTime.
func (k Keeper) GetAllExpiredRecords(ctx sdk.Context, currTime time.Time) (expiredRecordCIDs []string) {
// Gets an iterator for all timeslices from time 0 until the current block header time.
itr := k.RecordExpiryQueueIterator(ctx, ctx.BlockHeader().Time)
defer itr.Close()
for ; itr.Valid(); itr.Next() {
timeslice, err := helpers.BytesArrToStringArr(itr.Value())
if err != nil {
panic(err)
}
expiredRecordCIDs = append(expiredRecordCIDs, timeslice...)
}
return expiredRecordCIDs
}
// ProcessRecordExpiryQueue tries to renew expiring records (by collecting rent) else marks them as deleted.
func (k Keeper) ProcessRecordExpiryQueue(ctx sdk.Context) {
cids := k.GetAllExpiredRecords(ctx, ctx.BlockHeader().Time)
for _, cid := range cids {
record := k.GetRecord(ctx, cid)
// If record doesn't have an associated bond or if bond no longer exists, mark it deleted.
if record.BondId == "" || !k.bondKeeper.HasBond(ctx, record.BondId) {
record.Deleted = true
k.PutRecord(ctx, record)
k.DeleteRecordExpiryQueue(ctx, record)
return
}
// Try to renew the record by taking rent.
k.TryTakeRecordRent(ctx, record)
}
}
// TryTakeRecordRent tries to take rent from the record bond.
func (k Keeper) TryTakeRecordRent(ctx sdk.Context, record types.Record) {
params := k.GetParams(ctx)
rent := params.RecordRent
sdkErr := k.bondKeeper.TransferCoinsToModuleAccount(ctx, record.BondId, types.RecordRentModuleAccountName, sdk.NewCoins(rent))
if sdkErr != nil {
// Insufficient funds, mark record as deleted.
record.Deleted = true
k.PutRecord(ctx, record)
k.DeleteRecordExpiryQueue(ctx, record)
return
}
// Delete old expiry queue entry, create new one.
k.DeleteRecordExpiryQueue(ctx, record)
record.ExpiryTime = ctx.BlockHeader().Time.Add(params.RecordRentDuration).Format(time.RFC3339)
k.InsertRecordExpiryQueue(ctx, record)
// Save record.
record.Deleted = false
k.PutRecord(ctx, record)
k.AddBondToRecordIndexEntry(ctx, record.BondId, record.Id)
}
// GetModuleBalances gets the nameservice module account(s) balances. // GetModuleBalances gets the nameservice module account(s) balances.
func (k Keeper) GetModuleBalances(ctx sdk.Context) []*types.AccountBalance { func (k Keeper) GetModuleBalances(ctx sdk.Context) []*types.AccountBalance {
var balances []*types.AccountBalance var balances []*types.AccountBalance

View File

@ -1,7 +1,12 @@
package keeper package keeper
import ( import (
"bytes"
"fmt" "fmt"
"net/url"
"strings"
"time"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -9,9 +14,6 @@ import (
auctiontypes "github.com/tharsis/ethermint/x/auction/types" auctiontypes "github.com/tharsis/ethermint/x/auction/types"
"github.com/tharsis/ethermint/x/nameservice/helpers" "github.com/tharsis/ethermint/x/nameservice/helpers"
"github.com/tharsis/ethermint/x/nameservice/types" "github.com/tharsis/ethermint/x/nameservice/types"
"net/url"
"strings"
"time"
) )
func getAuthorityPubKey(pubKey cryptotypes.PubKey) string { func getAuthorityPubKey(pubKey cryptotypes.PubKey) string {
@ -596,6 +598,111 @@ func (k Keeper) SetAuthorityExpiryQueueTimeSlice(ctx sdk.Context, timestamp time
store.Set(getAuthorityExpiryQueueTimeKey(timestamp), bz) store.Set(getAuthorityExpiryQueueTimeKey(timestamp), bz)
} }
// ProcessAuthorityExpiryQueue tries to renew expiring authorities (by collecting rent) else marks them as expired.
func (k Keeper) ProcessAuthorityExpiryQueue(ctx sdk.Context) {
names := k.GetAllExpiredAuthorities(ctx, ctx.BlockHeader().Time)
for _, name := range names {
authority := k.GetNameAuthority(ctx, name)
// If authority doesn't have an associated bond or if bond no longer exists, mark it expired.
if authority.BondId == "" || !k.bondKeeper.HasBond(ctx, authority.BondId) {
authority.Status = types.AuthorityExpired
k.SetNameAuthority(ctx, name, &authority)
k.DeleteAuthorityExpiryQueue(ctx, name, authority)
ctx.Logger().Info(fmt.Sprintf("Marking authority expired as no bond present: %s", name))
return
}
// Try to renew the authority by taking rent.
k.TryTakeAuthorityRent(ctx, name, authority)
}
}
// DeleteAuthorityExpiryQueueTimeSlice deletes a specific authority expiry queue timeslice.
func (k Keeper) DeleteAuthorityExpiryQueueTimeSlice(ctx sdk.Context, timestamp time.Time) {
store := ctx.KVStore(k.storeKey)
store.Delete(getAuthorityExpiryQueueTimeKey(timestamp))
}
// DeleteAuthorityExpiryQueue deletes an authority name from the authority expiry queue.
func (k Keeper) DeleteAuthorityExpiryQueue(ctx sdk.Context, name string, authority types.NameAuthority) {
timeSlice := k.GetAuthorityExpiryQueueTimeSlice(ctx, authority.ExpiryTime)
newTimeSlice := []string{}
for _, existingName := range timeSlice {
if !bytes.Equal([]byte(existingName), []byte(name)) {
newTimeSlice = append(newTimeSlice, existingName)
}
}
if len(newTimeSlice) == 0 {
k.DeleteAuthorityExpiryQueueTimeSlice(ctx, authority.ExpiryTime)
} else {
k.SetAuthorityExpiryQueueTimeSlice(ctx, authority.ExpiryTime, newTimeSlice)
}
}
// GetAllExpiredAuthorities returns a concatenated list of all the timeslices before currTime.
func (k Keeper) GetAllExpiredAuthorities(ctx sdk.Context, currTime time.Time) (expiredAuthorityNames []string) {
// Gets an iterator for all timeslices from time 0 until the current block header time.
itr := k.AuthorityExpiryQueueIterator(ctx, ctx.BlockHeader().Time)
defer itr.Close()
for ; itr.Valid(); itr.Next() {
timeslice := []string{}
timeslice, err := helpers.BytesArrToStringArr(itr.Value())
if err != nil {
panic(err)
}
expiredAuthorityNames = append(expiredAuthorityNames, timeslice...)
}
return expiredAuthorityNames
}
// AuthorityExpiryQueueIterator returns all the authority expiry queue timeslices from time 0 until endTime.
func (k Keeper) AuthorityExpiryQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
store := ctx.KVStore(k.storeKey)
rangeEndBytes := sdk.InclusiveEndBytes(getAuthorityExpiryQueueTimeKey(endTime))
return store.Iterator(PrefixExpiryTimeToAuthoritiesIndex, rangeEndBytes)
}
// TryTakeAuthorityRent tries to take rent from the authority bond.
func (k Keeper) TryTakeAuthorityRent(ctx sdk.Context, name string, authority types.NameAuthority) {
ctx.Logger().Info(fmt.Sprintf("Trying to take rent for authority: %s", name))
params := k.GetParams(ctx)
rent := params.AuthorityRent
sdkErr := k.bondKeeper.TransferCoinsToModuleAccount(ctx, authority.BondId, types.AuthorityRentModuleAccountName, sdk.NewCoins(rent))
if sdkErr != nil {
// Insufficient funds, mark authority as expired.
authority.Status = types.AuthorityExpired
k.SetNameAuthority(ctx, name, &authority)
k.DeleteAuthorityExpiryQueue(ctx, name, authority)
ctx.Logger().Info(fmt.Sprintf("Insufficient funds in owner account to pay authority rent, marking as expired: %s", name))
return
}
// Delete old expiry queue entry, create new one.
k.DeleteAuthorityExpiryQueue(ctx, name, authority)
authority.ExpiryTime = ctx.BlockTime().Add(params.AuthorityRentDuration)
k.InsertAuthorityExpiryQueue(ctx, name, authority.ExpiryTime)
// Save authority.
authority.Status = types.AuthorityActive
k.SetNameAuthority(ctx, name, &authority)
k.AddBondToAuthorityIndexEntry(ctx, authority.BondId, name)
ctx.Logger().Info(fmt.Sprintf("Authority rent paid successfully: %s", name))
}
// ListNameAuthorityRecords - get all name authority records. // ListNameAuthorityRecords - get all name authority records.
func (k Keeper) ListNameAuthorityRecords(ctx sdk.Context) map[string]types.NameAuthority { func (k Keeper) ListNameAuthorityRecords(ctx sdk.Context) map[string]types.NameAuthority {
nameAuthorityRecords := make(map[string]types.NameAuthority) nameAuthorityRecords := make(map[string]types.NameAuthority)