package keeper
import (
"context"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
ctypes "github.com/cybercongress/go-cyber/v7/types"
bandwidthkeeper "github.com/cybercongress/go-cyber/v7/x/bandwidth/keeper"
bandwidthtypes "github.com/cybercongress/go-cyber/v7/x/bandwidth/types"
cyberbankkeeper "github.com/cybercongress/go-cyber/v7/x/cyberbank/keeper"
"github.com/cybercongress/go-cyber/v7/x/graph/types"
)
type msgServer struct {
*GraphKeeper
*IndexKeeper
authkeeper.AccountKeeper
*cyberbankkeeper.IndexedKeeper
*bandwidthkeeper.BandwidthMeter
}
func NewMsgServerImpl(
gk *GraphKeeper,
ik *IndexKeeper,
ak authkeeper.AccountKeeper,
bk *cyberbankkeeper.IndexedKeeper,
bm *bandwidthkeeper.BandwidthMeter,
) types.MsgServer {
return &msgServer{
gk,
ik,
ak,
bk,
bm,
}
}
var _ types.MsgServer = msgServer{}
func (k msgServer) Cyberlink(goCtx context.Context, msg *types.MsgCyberlink) (*types.MsgCyberlinkResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
var accNumber ctypes.AccNumber
addr, err := sdk.AccAddressFromBech32(msg.Neuron)
if err != nil {
return nil, err
}
acc := k.GetAccount(ctx, addr)
if acc != nil {
accNumber = ctypes.AccNumber(acc.GetAccountNumber())
} else {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "Invalid neuron address")
}
if ampers, ok := k.GetTotalStakesAmpere()[uint64(accNumber)]; ok {
if ampers == 0 {
return nil, types.ErrZeroPower
}
} else {
return nil, types.ErrZeroPower
}
cost := uint64(k.GetCurrentCreditPrice().MulInt64(int64(len(msg.Links) * 1000)).TruncateInt64())
currentBlockSpentBandwidth := k.GetCurrentBlockSpentBandwidth(ctx)
maxBlockBandwidth := k.GetMaxBlockBandwidth(ctx)
if !k.HasEnoughAccountBandwidthVolt(ctx, cost, addr) {
return nil, bandwidthtypes.ErrNotEnoughBandwidth
}
if (cost + currentBlockSpentBandwidth) > maxBlockBandwidth {
return nil, bandwidthtypes.ErrExceededMaxBlockBandwidth
}
err = k.BurnAccountBandwidthVolt(ctx, cost, addr)
if err != nil {
return nil, bandwidthtypes.ErrNotEnoughBandwidth
}
k.AddToBlockBandwidth(ctx, cost)
k.AddBurnedVolts(ctx, cost)
for _, link := range msg.Links {
fromCidNumber, exists := k.GetCidNumber(ctx, types.Cid(link.From))
if !exists {
continue
}
toCidNumber, exists := k.GetCidNumber(ctx, types.Cid(link.To))
if !exists {
continue
}
compactLink := types.NewLink(fromCidNumber, toCidNumber, accNumber)
if k.IndexKeeper.IsLinkExist(compactLink) {
return nil, types.ErrCyberlinkExist
}
if k.IndexKeeper.IsLinkExistInCache(ctx, compactLink) {
return nil, types.ErrCyberlinkExist
}
}
for _, link := range msg.Links {
fromCidNumber := k.GetOrPutCidNumber(ctx, types.Cid(link.From))
toCidNumber := k.GetOrPutCidNumber(ctx, types.Cid(link.To))
k.GraphKeeper.SaveLink(ctx, types.NewLink(fromCidNumber, toCidNumber, accNumber))
k.GraphKeeper.IncrementNeudeg(ctx, uint64(accNumber))
k.IndexKeeper.PutLink(ctx, types.NewLink(fromCidNumber, toCidNumber, accNumber))
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeCyberlink,
sdk.NewAttribute(types.AttributeKeyParticleFrom, link.From),
sdk.NewAttribute(types.AttributeKeyParticleTo, link.To),
),
)
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeCyberlink,
sdk.NewAttribute(types.AttributeKeyNeuron, msg.Neuron),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Neuron),
),
})
return &types.MsgCyberlinkResponse{}, nil
}