nameservice: implement processing record and authority expiry
This commit is contained in:
parent
8477b3d9cb
commit
7f70108a4a
9
init.sh
9
init.sh
@ -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."
|
||||||
|
|
||||||
|
@ -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{}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user