Skip to content
This repository has been archived by the owner on Oct 24, 2024. It is now read-only.

Add Resolver Module #84

Merged
merged 25 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# mycel
**mycel** is a blockchain built using Cosmos SDK and Tendermint and created with [Ignite CLI](https://ignite.com/cli).
# Mycel
**Mycel** is a Decentralized ID Infrastructure solution that resolves addresses such as websites, crypto wallets, IPFS, among many more accessible through a single domain with name resolution support in DNS, IBC and smart contracts.

## Dependencies
- Go `1.20.2`
Expand Down Expand Up @@ -152,9 +152,7 @@ curl https://get.ignite.com/mycel-domain/mycel@latest! | sudo bash
```

## Learn more

- [Ignite CLI](https://ignite.com/cli)
- [Tutorials](https://docs.ignite.com/guide)
- [Ignite CLI docs](https://docs.ignite.com)
- [Cosmos SDK docs](https://docs.cosmos.network)
- [Developer Chat](https://discord.gg/ignite)
- [Website](https://mycel.domains)
- [Mycel Docs](https://docs.mycel.domains)
- [Discord](https://discord.gg/h2jSkBETan)
- [X](https://twitter.com/myceldomain)
22 changes: 22 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ import (
epochsmodulekeeper "github.com/mycel-domain/mycel/x/epochs/keeper"
epochsmoduletypes "github.com/mycel-domain/mycel/x/epochs/types"

resolvermodule "github.com/mycel-domain/mycel/x/resolver"
resolvermodulekeeper "github.com/mycel-domain/mycel/x/resolver/keeper"
resolvermoduletypes "github.com/mycel-domain/mycel/x/resolver/types"
// this line is used by starport scaffolding # stargate/app/moduleImport

appparams "github.com/mycel-domain/mycel/app/params"
Expand Down Expand Up @@ -232,6 +235,7 @@ var (
// my modules
registrymodule.AppModuleBasic{},
epochsmodule.AppModuleBasic{},
resolvermodule.AppModuleBasic{},
// this line is used by starport scaffolding # stargate/app/moduleBasic
)

Expand Down Expand Up @@ -317,6 +321,8 @@ type App struct {
// my mnodules
RegistryKeeper registrymodulekeeper.Keeper
EpochsKeeper epochsmodulekeeper.Keeper

ResolverKeeper resolvermodulekeeper.Keeper
// this line is used by starport scaffolding # stargate/app/keeperDeclaration

// mm is the module manager
Expand Down Expand Up @@ -403,6 +409,7 @@ func NewApp(
// my modules
registrymoduletypes.StoreKey,
epochsmoduletypes.StoreKey,
resolvermoduletypes.StoreKey,
// this line is used by starport scaffolding # stargate/app/storeKey
)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
Expand Down Expand Up @@ -683,6 +690,16 @@ func NewApp(
)
registryModule := registrymodule.NewAppModule(appCodec, app.RegistryKeeper, app.AccountKeeper, app.BankKeeper)

app.ResolverKeeper = *resolvermodulekeeper.NewKeeper(
appCodec,
keys[resolvermoduletypes.StoreKey],
keys[resolvermoduletypes.MemStoreKey],
app.GetSubspace(resolvermoduletypes.ModuleName),

app.RegistryKeeper,
)
resolverModule := resolvermodule.NewAppModule(appCodec, app.ResolverKeeper, app.AccountKeeper, app.BankKeeper)

// this line is used by starport scaffolding # stargate/app/keeperDefinition

/**** IBC Routing ****/
Expand Down Expand Up @@ -754,6 +771,7 @@ func NewApp(
// my modules
registryModule,
epochsModule,
resolverModule,
// this line is used by starport scaffolding # stargate/app/appModule

crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), // always be last to make sure that it checks for all invariants and not only part of them
Expand Down Expand Up @@ -791,6 +809,7 @@ func NewApp(
// my modules
registrymoduletypes.ModuleName,
epochsmoduletypes.ModuleName,
resolvermoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/beginBlockers
)

Expand Down Expand Up @@ -821,6 +840,7 @@ func NewApp(
// my modules
registrymoduletypes.ModuleName,
epochsmoduletypes.ModuleName,
resolvermoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/endBlockers
)

Expand Down Expand Up @@ -857,6 +877,7 @@ func NewApp(
// my modules
registrymoduletypes.ModuleName,
epochsmoduletypes.ModuleName,
resolvermoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/initGenesis
}
app.mm.SetOrderInitGenesis(genesisModuleOrder...)
Expand Down Expand Up @@ -1119,6 +1140,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino
// my modules
paramsKeeper.Subspace(registrymoduletypes.ModuleName)
paramsKeeper.Subspace(epochsmoduletypes.ModuleName)
paramsKeeper.Subspace(resolvermoduletypes.ModuleName)
// this line is used by starport scaffolding # stargate/app/paramSubspace

return paramsKeeper
Expand Down
1 change: 0 additions & 1 deletion app/simulation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ func BenchmarkSimulation(b *testing.B) {
appOptions[flags.FlagHome] = app.DefaultNodeHome
appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue


wasmOpt := []wasmkeeper.Option{}

bApp := app.New(
Expand Down
8 changes: 8 additions & 0 deletions cmd/myceld/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/spf13/cast"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

// this line is used by starport scaffolding # root/moduleImport

// CosmWasm
Expand All @@ -45,6 +46,7 @@ import (

"github.com/mycel-domain/mycel/app"
appparams "github.com/mycel-domain/mycel/app/params"
"github.com/mycel-domain/mycel/cmd/myceld/dns"
)

// NewRootCmd creates a new root command for a Cosmos SDK application
Expand Down Expand Up @@ -154,6 +156,11 @@ func initRootCmd(
txCommand(),
keys.Commands(app.DefaultNodeHome),
)

// add DNS command
rootCmd.AddCommand(
dns.DnsCommand(),
)
}

// queryCommand returns the sub-command to send queries to the app
Expand Down Expand Up @@ -208,6 +215,7 @@ func txCommand() *cobra.Command {
return cmd
}


func addModuleInitFlags(startCmd *cobra.Command) {
crisis.AddModuleInitFlags(startCmd)
// this line is used by starport scaffolding # root/arguments
Expand Down
234 changes: 234 additions & 0 deletions cmd/myceld/dns/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package dns

import (
"context"
"fmt"
"log"
"net"
"strings"

"github.com/miekg/dns"
resolver "github.com/mycel-domain/mycel/x/resolver/types"
"google.golang.org/grpc"

"github.com/spf13/cobra"
)

type grpcService struct {
grpcConn *grpc.ClientConn
}

type DnsRecord interface{}

func (s *grpcService) QueryDnsToMycelResolver(domain string, recordType string) (dnsRecord DnsRecord) {

domain = strings.Trim(domain, ".")
division := strings.Index(domain, ".")

argName := domain[:division]
argParent := domain[division+1:]

queryClient := resolver.NewQueryClient(s.grpcConn)

params := &resolver.QueryDnsRecordRequest{
DomainName: argName,
DomainParent: argParent,
DnsRecordType: recordType,
}

ctx := context.Background()

res, err := queryClient.DnsRecord(ctx, params)
if err != nil {
log.Printf("QueryDnsToMycelResolver: %v", err)
return nil
}

if found := res.Value != nil; found {
value := res.Value.Value
switch recordType {
case "A", "AAAA":
dnsRecord = net.ParseIP(value)
case "CNAME", "MX", "NS":
dnsRecord = value
case "TXT":
dnsRecord = []string{value}
default:
dnsRecord = nil
}
}
return dnsRecord
}

func (s *grpcService) QueryDnsToDefaultResolver(domain string, recordType string) DnsRecord {
switch recordType {
case "A":
ips, err := net.LookupIP(domain)
if err != nil {
return nil
}
for _, ip := range ips {
if ipv4 := ip.To4(); ipv4 != nil {
return ipv4
}
}
case "AAAA":
ips, err := net.LookupIP(domain)
if err != nil {
return nil
}
for _, ip := range ips {
if ipv4 := ip.To4(); ipv4 == nil {
return ip
}
}
case "CNAME":
cname, err := net.LookupCNAME(domain)
if err != nil {
return nil
}
return cname
case "MX":
mxs, err := net.LookupMX(domain)
if err != nil || len(mxs) == 0 {
return nil
}
return mxs[0].Host
case "NS":
nss, err := net.LookupNS(domain)
if err != nil || len(nss) == 0 {
return nil
}
return nss[0].Host
case "TXT":
txts, err := net.LookupTXT(domain)
if err != nil {
return nil
}
return txts
default:
return nil
}
return nil
}

func (s *grpcService) QueryDns(domain string, recordType string) (dnsRecord DnsRecord) {
dnsRecord = s.QueryDnsToMycelResolver(domain, recordType)
log.Printf("MycelResolver: %s %s %v", domain, recordType, dnsRecord)
if dnsRecord == nil {
dnsRecord = s.QueryDnsToDefaultResolver(domain, recordType)
log.Printf("DefaultResolver: %s %s %v", domain, recordType, dnsRecord)
}
return dnsRecord
}

func (s *grpcService) HandleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
msg := dns.Msg{}
msg.SetReply(r)

domain := msg.Question[0].Name
found := false

switch r.Question[0].Qtype {
case dns.TypeA:
msg.Authoritative = true
record := s.QueryDns(domain, "A")
if ip, ok := record.(net.IP); ok && ip != nil {
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 600},
A: ip,
})
found = true
}
case dns.TypeAAAA:
record := s.QueryDns(domain, "AAAA")
if ip, ok := record.(net.IP); ok && ip != nil {
msg.Answer = append(msg.Answer, &dns.AAAA{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 600},
AAAA: ip,
})
found = true
}
case dns.TypeCNAME:
record := s.QueryDns(domain, "CNAME")
if cname, ok := record.(string); ok && cname != "" {
msg.Answer = append(msg.Answer, &dns.CNAME{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 600},
Target: cname,
})
found = true
}
case dns.TypeMX:
record := s.QueryDns(domain, "MX")
if mx, ok := record.(string); ok && mx != "" {
msg.Answer = append(msg.Answer, &dns.MX{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 600},
Mx: mx,
})
found = true
}
case dns.TypeNS:
record := s.QueryDns(domain, "NS")
if ns, ok := record.(string); ok && ns != "" {
msg.Answer = append(msg.Answer, &dns.NS{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 600},
Ns: ns,
})
found = true
}
case dns.TypeTXT:
record := s.QueryDns(domain, "TXT")
if txt, ok := record.([]string); ok && len(txt) > 0 {
msg.Answer = append(msg.Answer, &dns.TXT{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 600},
Txt: txt,
})
found = true
}
default:
break
}

if !found {
msg.SetRcode(r, dns.RcodeNameError)
}

w.WriteMsg(&msg)
}

func RunDnsServer(nodeAddress string, listenPort int) error {
grpcConn, err := grpc.Dial(nodeAddress,
grpc.WithInsecure(),
)
if err != nil {
log.Fatalf("Failed to connect to node: %v", err)
}
defer grpcConn.Close()

grpc := grpcService{
grpcConn: grpcConn,
}

dns.HandleFunc(".", grpc.HandleDNSRequest)
server := &dns.Server{Addr: fmt.Sprintf(":%d", listenPort), Net: "udp"}
fmt.Printf("Starting DNS server at %s\n", server.Addr)
err = server.ListenAndServe()
return err
}

// DnsCommand returns command to start DNS server
func DnsCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "dns",
Short: "Run DNS server",
RunE: func(cmd *cobra.Command, _ []string) (err error) {
listenPort, _ := cmd.Flags().GetInt("port")
nodeAddress, _ := cmd.Flags().GetString("nodeAddress")
err = RunDnsServer(nodeAddress, listenPort)
return err
},
}
cmd.PersistentFlags().Int("port", 53, "Port to listen on")
cmd.PersistentFlags().String("nodeAddress", "localhost:9090", "Mycel node address")
return cmd
}
Loading
Loading