diff --git a/basic/Dockerfile b/basic/Dockerfile index 0d35b64..47fea58 100644 --- a/basic/Dockerfile +++ b/basic/Dockerfile @@ -1,8 +1,8 @@ -FROM golang:1.15.5 +FROM golang:1.18 WORKDIR /go/src/app COPY ./ . RUN go get -d -v ./... RUN go install -v ./... -RUN cd basic && make +RUN cd basic && make diff --git a/basic/README b/basic/README.md similarity index 100% rename from basic/README rename to basic/README.md diff --git a/basic/cleanup.go b/basic/cleanup.go deleted file mode 100644 index 773c015..0000000 --- a/basic/cleanup.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "time" - - "github.com/jmoiron/sqlx" -) - -// every hour, delete all very old events -func cleanupRoutine(db *sqlx.DB) { - for { - time.Sleep(60 * time.Minute) - db.Exec(`DELETE FROM event WHERE created_at < $1`, time.Now().AddDate(0, -3, 0)) - } -} diff --git a/basic/delete.go b/basic/delete.go deleted file mode 100644 index 1f6d5cf..0000000 --- a/basic/delete.go +++ /dev/null @@ -1,6 +0,0 @@ -package main - -func (b *BasicRelay) DeleteEvent(id string, pubkey string) error { - _, err := b.DB.Exec("DELETE FROM events WHERE id = $1 AND pubkey = $2") - return err -} diff --git a/basic/docker-compose.yml b/basic/docker-compose.yml index ee6176b..918a509 100644 --- a/basic/docker-compose.yml +++ b/basic/docker-compose.yml @@ -13,7 +13,7 @@ services: condition: service_healthy ports: - 2700:2700 - command: "./basic/relayer" + command: "./basic/relayer-basic" postgres: image: postgres @@ -29,4 +29,4 @@ services: test: ["CMD-SHELL", "pg_isready -U nostr"] # database username here - nostr, should be changed if other user interval: 10s timeout: 5s - retries: 5 \ No newline at end of file + retries: 5 diff --git a/basic/main.go b/basic/main.go index 3a4fbd1..ce15b8e 100644 --- a/basic/main.go +++ b/basic/main.go @@ -1,44 +1,69 @@ package main import ( + "encoding/json" "fmt" + "time" + "github.com/fiatjaf/go-nostr" "github.com/fiatjaf/relayer" - "github.com/jmoiron/sqlx" - "github.com/jmoiron/sqlx/reflectx" + "github.com/fiatjaf/relayer/storage/postgresql" "github.com/kelseyhightower/envconfig" ) -type BasicRelay struct { +type Relay struct { PostgresDatabase string `envconfig:"POSTGRESQL_DATABASE"` - - DB *sqlx.DB } -func (b *BasicRelay) Name() string { +func (r *Relay) Name() string { return "BasicRelay" } -func (b *BasicRelay) Init() error { - err := envconfig.Process("", b) +func (r *Relay) Storage() relayer.Storage { + return &postgresql.PostgresBackend{DatabaseURL: r.PostgresDatabase} +} + +func (r *Relay) Init() error { + err := envconfig.Process("", r) if err != nil { return fmt.Errorf("couldn't process envconfig: %w", err) } - if db, err := initDB(b.PostgresDatabase); err != nil { - return fmt.Errorf("failed to open database: %w", err) - } else { - db.Mapper = reflectx.NewMapperFunc("json", sqlx.NameMapper) - b.DB = db - } + // every hour, delete all very old events + go func() { + db := r.Storage().(*postgresql.PostgresBackend) - go cleanupRoutine(b.DB) + for { + time.Sleep(60 * time.Minute) + db.DB.Exec(`DELETE FROM event WHERE created_at < $1`, time.Now().AddDate(0, -3, 0)) // 3 months + } + }() return nil } -func main() { - var b BasicRelay +func (r *Relay) AcceptEvent(evt *nostr.Event) bool { + // block events that are too large + jsonb, _ := json.Marshal(evt) + if len(jsonb) > 10000 { + return false + } - relayer.Start(&b) + return true +} + +func (r *Relay) BeforeSave(evt *nostr.Event) { + // do nothing +} + +func (r *Relay) AfterSave(evt *nostr.Event) { + // delete all but the 100 most recent ones for each key + r.Storage().(*postgresql.PostgresBackend).DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND created_at < ( + SELECT created_at FROM event WHERE pubkey = $1 + ORDER BY created_at DESC OFFSET 100 LIMIT 1 + )`, evt.PubKey, evt.Kind) +} + +func main() { + relayer.Start(&Relay{}) } diff --git a/basic/query.go b/basic/query.go deleted file mode 100644 index 85f01cd..0000000 --- a/basic/query.go +++ /dev/null @@ -1,158 +0,0 @@ -package main - -import ( - "database/sql" - "encoding/hex" - "errors" - "fmt" - "strconv" - "strings" - "time" - - "github.com/fiatjaf/go-nostr" - "github.com/rs/zerolog/log" -) - -func (b *BasicRelay) QueryEvents(filter *nostr.Filter) (events []nostr.Event, err error) { - var conditions []string - var params []any - - if filter == nil { - err = errors.New("filter cannot be null") - return - } - - if filter.IDs != nil { - if len(filter.IDs) > 500 { - // too many ids, fail everything - return - } - - likeids := make([]string, 0, len(filter.IDs)) - for _, id := range filter.IDs { - // to prevent sql attack here we will check if - // these ids are valid 32byte hex - parsed, err := hex.DecodeString(id) - if err != nil || len(parsed) <= 32 { - continue - } - likeids = append(likeids, fmt.Sprintf("id LIKE '%x%%'", parsed)) - } - if len(likeids) == 0 { - // ids being [] mean you won't get anything - return - } - conditions = append(conditions, "("+strings.Join(likeids, " OR ")+")") - } - - if filter.Authors != nil { - if len(filter.Authors) > 500 { - // too many authors, fail everything - return - } - - likekeys := make([]string, 0, len(filter.Authors)) - for _, key := range filter.Authors { - // to prevent sql attack here we will check if - // these keys are valid 32byte hex - parsed, err := hex.DecodeString(key) - if err != nil || len(parsed) != 32 { - continue - } - likekeys = append(likekeys, fmt.Sprintf("pubkey LIKE '%x%%'", parsed)) - } - if len(likekeys) == 0 { - // authors being [] mean you won't get anything - return - } - conditions = append(conditions, "("+strings.Join(likekeys, " OR ")+")") - } - - if filter.Kinds != nil { - if len(filter.Kinds) > 10 { - // too many kinds, fail everything - return - } - - if len(filter.Kinds) == 0 { - // kinds being [] mean you won't get anything - return - } - // no sql injection issues since these are ints - inkinds := make([]string, len(filter.Kinds)) - for i, kind := range filter.Kinds { - inkinds[i] = strconv.Itoa(kind) - } - conditions = append(conditions, `kind IN (`+strings.Join(inkinds, ",")+`)`) - } - - tagQuery := make([]string, 0, 1) - for _, values := range filter.Tags { - if len(values) == 0 { - // any tag set to [] is wrong - return - } - - // add these tags to the query - tagQuery = append(tagQuery, values...) - - if len(tagQuery) > 10 { - // too many tags, fail everything - return - } - } - - if len(tagQuery) > 0 { - arrayBuild := make([]string, len(tagQuery)) - for i, tagValue := range tagQuery { - arrayBuild[i] = "?" - params = append(params, tagValue) - } - - // we use a very bad implementation in which we only check the tag values and - // ignore the tag names - conditions = append(conditions, - "tagvalues && ARRAY["+strings.Join(arrayBuild, ",")+"]") - } - - if filter.Since != nil { - conditions = append(conditions, "created_at > ?") - params = append(params, filter.Since.Unix()) - } - if filter.Until != nil { - conditions = append(conditions, "created_at < ?") - params = append(params, filter.Until.Unix()) - } - - if len(conditions) == 0 { - // fallback - conditions = append(conditions, "true") - } - - query := b.DB.Rebind(`SELECT - id, pubkey, created_at, kind, tags, content, sig - FROM event WHERE ` + - strings.Join(conditions, " AND ") + - " ORDER BY created_at LIMIT 100") - - rows, err := b.DB.Query(query, params...) - if err != nil && err != sql.ErrNoRows { - log.Warn().Err(err).Interface("filter", filter).Str("query", query). - Msg("failed to fetch events") - return nil, fmt.Errorf("failed to fetch events: %w", err) - } - - for rows.Next() { - var evt nostr.Event - var timestamp int64 - err := rows.Scan(&evt.ID, &evt.PubKey, ×tamp, - &evt.Kind, &evt.Tags, &evt.Content, &evt.Sig) - if err != nil { - return nil, fmt.Errorf("failed to scan row: %w", err) - } - evt.CreatedAt = time.Unix(timestamp, 0) - events = append(events, evt) - } - - return events, nil -} diff --git a/basic/save.go b/basic/save.go deleted file mode 100644 index 0c9b4ee..0000000 --- a/basic/save.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - "github.com/fiatjaf/go-nostr" -) - -func (b *BasicRelay) SaveEvent(evt *nostr.Event) error { - // disallow large contents - if len(evt.Content) > 1000 { - return errors.New("event content too large") - } - - // react to different kinds of events - if evt.Kind == nostr.KindSetMetadata || evt.Kind == nostr.KindContactList || (10000 <= evt.Kind && evt.Kind < 20000) { - // delete past events from this user - b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2`, evt.PubKey, evt.Kind) - } else if evt.Kind == nostr.KindRecommendServer { - // delete past recommend_server events equal to this one - b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`, - evt.PubKey, evt.Kind, evt.Content) - } else { - // delete all but the 100 most recent ones - b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND created_at < ( - SELECT created_at FROM event WHERE pubkey = $1 - ORDER BY created_at DESC OFFSET 100 LIMIT 1 - )`, - evt.PubKey, evt.Kind) - } - - // insert - tagsj, _ := json.Marshal(evt.Tags) - _, err := b.DB.Exec(` - INSERT INTO event (id, pubkey, created_at, kind, tags, content, sig) - VALUES ($1, $2, $3, $4, $5, $6, $7) - `, evt.ID, evt.PubKey, evt.CreatedAt.Unix(), evt.Kind, tagsj, evt.Content, evt.Sig) - if err != nil { - if strings.Index(err.Error(), "UNIQUE") != -1 { - // already exists - return nil - } - - return fmt.Errorf("failed to save event %s: %w", evt.ID, err) - } - - // delete ephemeral events after a minute - go func() { - time.Sleep(75 * time.Second) - b.DB.Exec("DELETE FROM event WHERE id = $1", evt.ID) - }() - - return nil -} diff --git a/expensive/.gitignore b/expensive/.gitignore new file mode 100644 index 0000000..d7d0b22 --- /dev/null +++ b/expensive/.gitignore @@ -0,0 +1 @@ +relayer-expensive diff --git a/expensive/Makefile b/expensive/Makefile new file mode 100644 index 0000000..28eabee --- /dev/null +++ b/expensive/Makefile @@ -0,0 +1,2 @@ +relayer-expensive: $(shell find .. -name "*.go") + CC=$$(which musl-gcc) go build -ldflags='-s -w -linkmode external -extldflags "-static"' -o ./relayer-expensive diff --git a/expensive/README.md b/expensive/README.md new file mode 100644 index 0000000..fb300d3 --- /dev/null +++ b/expensive/README.md @@ -0,0 +1,31 @@ +expensive-relay, a sybil-free corner of nostr +============================================= + + - a nostr relay implementation based on relayer. + - uses postgres, which I think must be over version 12 since it uses generated columns. + - requires users to manually register themselves to be able to publish events and pay a fee. this should prevent spam. + - aside from that it's basically the same thing as relayer basic. + +running +------- + +this requires a recent CLN version with Commando. + +grab a binary from the releases page and run it with the following environment variables: + + POSTGRESQL_DATABASE=postgresql://... + CLN_NODE_ID=02fed8723... + CLN_HOST=127.0.0.1:9735 + CLN_RUNE=... + TICKET_PRICE_SATS=500 + +adjust the values above accordingly. + +compiling +--------- + +if you know Go you already know this: + + go install github.com/fiatjaf/relayer/expensive + +or something like that. diff --git a/expensive/handler.go b/expensive/handler.go new file mode 100644 index 0000000..f0657d8 --- /dev/null +++ b/expensive/handler.go @@ -0,0 +1,68 @@ +package main + +import ( + "encoding/json" + "net/http" +) + +func handleWebpage(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html") + w.Write([]byte(` + +expensive relay +

expensive relay

+https://github.com/fiatjaf/expensive-relay +

this is a nostr relay that only accepts events published from keys that pay a registration fee. this is an antispam measure. you can still be banned if you're spamming or doing something bad.

+

to register your nostr public key, type it below and click the button.

+
+ + +
+

+ + + + + + `)) +} + +func handleInvoice(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + invoice, err := generateInvoice(r.URL.Query().Get("pubkey")) + if err != nil { + json.NewEncoder(w).Encode(struct { + Error string `json:"error"` + }{err.Error()}) + } else { + json.NewEncoder(w).Encode(struct { + Invoice string `json:"bolt11"` + }{invoice}) + } +} diff --git a/expensive/lightning.go b/expensive/lightning.go new file mode 100644 index 0000000..845a3f5 --- /dev/null +++ b/expensive/lightning.go @@ -0,0 +1,78 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + + lnsocket "github.com/jb55/lnsocket/go" + "github.com/tidwall/gjson" +) + +func generateLabel(pubkey string) string { return fmt.Sprintf("relayer-expensive:ticket:%s", pubkey) } + +func generateInvoice(pubkey string) (string, error) { + cln := lnsocket.LNSocket{} + cln.GenKey() + + err := cln.ConnectAndInit(r.CLNHost, r.CLNNodeId) + if err != nil { + return "", err + } + defer cln.Disconnect() + + // check if there is an invoice already + jparams, _ := json.Marshal(map[string]any{ + "label": generateLabel(pubkey), + }) + result, _ := cln.Rpc(r.CLNRune, "listinvoices", string(jparams)) + if gjson.Get(result, "invoices.#").Int() == 1 { + return gjson.Get(result, "invoices.1.bolt11").String(), nil + } + + // otherwise generate an invoice + jparams, _ = json.Marshal(map[string]any{ + "amount_msat": r.TicketPriceSats * 1000, + "label": generateLabel(pubkey), + "description": fmt.Sprintf("%s's ticket for writing to relayer-expensive", pubkey), + }) + result, err = cln.Rpc(r.CLNRune, "invoice", string(jparams)) + if err != nil { + return "", err + } + + resErr := gjson.Get(result, "error") + if resErr.Type != gjson.Null { + if resErr.Type == gjson.JSON { + return "", errors.New(resErr.Get("message").String()) + } else if resErr.Type == gjson.String { + return "", errors.New(resErr.String()) + } + return "", fmt.Errorf("Unknown commando error: '%v'", resErr) + } + + invoice := gjson.Get(result, "result.bolt11") + if invoice.Type != gjson.String { + return "", fmt.Errorf("No bolt11 result found in invoice response, got %v", result) + } + + return invoice.String(), nil +} + +func checkInvoicePaidOk(pubkey string) bool { + cln := lnsocket.LNSocket{} + cln.GenKey() + + err := cln.ConnectAndInit(r.CLNHost, r.CLNNodeId) + if err != nil { + return false + } + defer cln.Disconnect() + + jparams, _ := json.Marshal(map[string]any{ + "label": generateLabel(pubkey), + }) + result, _ := cln.Rpc(r.CLNRune, "listinvoices", string(jparams)) + + return gjson.Get(result, "invoices.0.paid").String() == "paid" +} diff --git a/expensive/main.go b/expensive/main.go new file mode 100644 index 0000000..b843430 --- /dev/null +++ b/expensive/main.go @@ -0,0 +1,84 @@ +package main + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/fiatjaf/go-nostr" + "github.com/fiatjaf/relayer" + "github.com/fiatjaf/relayer/storage/postgresql" + "github.com/kelseyhightower/envconfig" +) + +type Relay struct { + PostgresDatabase string `envconfig:"POSTGRESQL_DATABASE"` + CLNNodeId string `envconfig:"CLN_NODE_ID"` + CLNHost string `envconfig:"CLN_HOST"` + CLNRune string `envconfig:"CLN_RUNE"` + TicketPriceSats int64 `envconfig:"TICKET_PRICE_SATS"` +} + +var r = &Relay{} + +func (r *Relay) Name() string { + return "ExpensiveRelay" +} + +func (r *Relay) Storage() relayer.Storage { + return &postgresql.PostgresBackend{DatabaseURL: r.PostgresDatabase} +} + +func (r *Relay) Init() error { + err := envconfig.Process("", r) + if err != nil { + return fmt.Errorf("couldn't process envconfig: %w", err) + } + + // every hour, delete all very old events + go func() { + db := r.Storage().(*postgresql.PostgresBackend) + + for { + time.Sleep(60 * time.Minute) + db.DB.Exec(`DELETE FROM event WHERE created_at < $1`, time.Now().AddDate(0, -6, 0)) // 6 months + } + }() + + // special handlers + relayer.Router.Path("/").HandlerFunc(handleWebpage) + relayer.Router.Path("/invoice").HandlerFunc(handleInvoice) + + return nil +} + +func (r *Relay) AcceptEvent(evt *nostr.Event) bool { + // only accept they have a good preimage for a paid invoice for their public key + if !checkInvoicePaidOk(evt.PubKey) { + return false + } + + // block events that are too large + jsonb, _ := json.Marshal(evt) + if len(jsonb) > 100000 { + return false + } + + return true +} + +func (r *Relay) BeforeSave(evt *nostr.Event) { + // do nothing +} + +func (r *Relay) AfterSave(evt *nostr.Event) { + // delete all but the 1000 most recent ones for each key + r.Storage().(*postgresql.PostgresBackend).DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND created_at < ( + SELECT created_at FROM event WHERE pubkey = $1 + ORDER BY created_at DESC OFFSET 1000 LIMIT 1 + )`, evt.PubKey, evt.Kind) +} + +func main() { + relayer.Start(r) +} diff --git a/go.mod b/go.mod index bf52b84..20335fe 100644 --- a/go.mod +++ b/go.mod @@ -6,17 +6,52 @@ require ( github.com/fiatjaf/go-nostr v0.7.3 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 + github.com/jb55/lnsocket/go v0.0.0-20220315220004-e1e6b88a0bfc github.com/jmoiron/sqlx v1.3.1 github.com/kelseyhightower/envconfig v1.4.0 - github.com/lib/pq v1.8.0 github.com/rs/cors v1.7.0 github.com/rs/zerolog v1.20.0 + github.com/tidwall/gjson v1.14.1 ) require ( + github.com/aead/siphash v1.0.1 // indirect + github.com/btcsuite/btcd v0.23.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect + github.com/btcsuite/btcd/btcutil v1.1.1 // indirect + github.com/btcsuite/btcd/btcutil/psbt v1.1.4 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect + github.com/btcsuite/btcwallet v0.15.1 // indirect + github.com/btcsuite/btcwallet/wallet/txauthor v1.2.3 // indirect + github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 // indirect + github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0 // indirect + github.com/btcsuite/btcwallet/walletdb v1.4.0 // indirect + github.com/btcsuite/btcwallet/wtxmgr v1.5.0 // indirect + github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect + github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/decred/dcrd/lru v1.0.0 // indirect + github.com/go-errors/errors v1.0.1 // indirect + github.com/kkdai/bstream v1.0.0 // indirect + github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // indirect + github.com/lightninglabs/neutrino v0.14.2 // indirect + github.com/lightningnetwork/lnd v0.15.0-beta // indirect + github.com/lightningnetwork/lnd/clock v1.1.0 // indirect + github.com/lightningnetwork/lnd/queue v1.1.0 // indirect + github.com/lightningnetwork/lnd/ticker v1.1.0 // indirect + github.com/lightningnetwork/lnd/tlv v1.0.3 // indirect + github.com/lightningnetwork/lnd/tor v1.0.1 // indirect + github.com/miekg/dns v1.1.43 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/valyala/fastjson v1.6.3 // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect ) + +replace github.com/jb55/lnsocket/go => /home/fiatjaf/comp/lnsocket/go diff --git a/go.sum b/go.sum index 0e80f3e..d4895f4 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,69 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= +github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.22.0-beta.0.20220204213055-eaf0459ff879/go.mod h1:osu7EoKiL36UThEgzYPqdRaxeo0NU8VoXqgcnwpey0g= +github.com/btcsuite/btcd v0.22.0-beta.0.20220207191057-4dc4ff7963b4/go.mod h1:7alexyj/lHlOtr2PJK7L/+HDJZpcGDn/pAU98r7DY08= +github.com/btcsuite/btcd v0.22.0-beta.0.20220316175102-8d5c75c28923/go.mod h1:taIcYprAW2g6Z9S0gGUxyR+zDwimyDMK5ePOX+iJ2ds= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd v0.23.1 h1:IB8cVQcC2X5mHbnfirLG5IZnkWYNTPlLZVrxUYSotbE= +github.com/btcsuite/btcd v0.23.1/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= +github.com/btcsuite/btcd/btcec/v2 v2.1.1/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.1 h1:hDcDaXiP0uEzR8Biqo2weECKqEw0uHDZ9ixIWevVQqY= +github.com/btcsuite/btcd/btcutil v1.1.1/go.mod h1:nbKlBMNm9FGsdvKvu0essceubPiAcI57pYBNnsLAa34= +github.com/btcsuite/btcd/btcutil/psbt v1.1.4 h1:Edx4AfBn+YPam2KP5AobDitulGp4r1Oibm8oruzkMdI= +github.com/btcsuite/btcd/btcutil/psbt v1.1.4/go.mod h1:9AyU6EQVJ9Iw9zPyNT1lcdHd6cnEZdno5wLu5FY74os= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/btcwallet v0.15.1 h1:SKfh/l2Bgz9sJwHZvfiVbZ8Pl3N/8fFcWWXzsAPz9GU= +github.com/btcsuite/btcwallet v0.15.1/go.mod h1:7OFsQ8ypiRwmr67hE0z98uXgJgXGAihE79jCib9x6ag= +github.com/btcsuite/btcwallet/wallet/txauthor v1.2.3 h1:M2yr5UlULvpqtxUqpMxTME/pA92Z9cpqeyvAFk9lAg0= +github.com/btcsuite/btcwallet/wallet/txauthor v1.2.3/go.mod h1:T2xSiKGpUkSLCh68aF+FMXmKK9mFqNdHl9VaqOr+JjU= +github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 h1:BtEN5Empw62/RVnZ0VcJaVtVlBijnLlJY+dwjAye2Bg= +github.com/btcsuite/btcwallet/wallet/txrules v1.2.0/go.mod h1:AtkqiL7ccKWxuLYtZm8Bu8G6q82w4yIZdgq6riy60z0= +github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0 h1:wZnOolEAeNOHzHTnznw/wQv+j35ftCIokNrnOTOU5o8= +github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= +github.com/btcsuite/btcwallet/walletdb v1.3.5/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU= +github.com/btcsuite/btcwallet/walletdb v1.4.0 h1:/C5JRF+dTuE2CNMCO/or5N8epsrhmSM4710uBQoYPTQ= +github.com/btcsuite/btcwallet/walletdb v1.4.0/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU= +github.com/btcsuite/btcwallet/wtxmgr v1.5.0 h1:WO0KyN4l6H3JWnlFxfGR7r3gDnlGT7W2cL8vl6av4SU= +github.com/btcsuite/btcwallet/wtxmgr v1.5.0/go.mod h1:TQVDhFxseiGtZwEPvLgtfyxuNUDsIdaJdshvWzR0HJ4= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -27,89 +72,280 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dvyukov/go-fuzz v0.0.0-20210602112143-b1f3d6f4ef4e h1:qTP1telKJHlToHlwPQNmVg4yfMDMHe4Z3SYmzkrvA2M= +github.com/fergusstrange/embedded-postgres v1.10.0 h1:YnwF6xAQYmKLAXXrrRx4rHDLih47YJwVPvg8jeKfdNg= github.com/fiatjaf/go-nostr v0.7.3 h1:Z95U2qTTj3a41+ybopYjfKZ+bMpNFM43ARA7B4IOYVs= github.com/fiatjaf/go-nostr v0.7.3/go.mod h1:pbJCdZzBKPB8wgQDipS5POnOV1afhcFzJUIwJ5qKSrU= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/pgconn v1.10.0 h1:4EYhlDVEMsJ30nNj0mmgwIUXoq7e9sMJrVC2ED6QlCU= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgtype v1.8.1 h1:9k0IXtdJXHJbyAWQgbWr1lU+MEhPXZz6RIXxfR5oxXs= +github.com/jackc/pgx/v4 v4.13.0 h1:JCjhT5vmhMAf/YwBHLvrBn4OGdIQBiFG6ym8Zmdx570= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE= github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8= +github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= -github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg= +github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= +github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= +github.com/lightninglabs/neutrino v0.14.2 h1:yrnZUCYMZ5ECtXhgDrzqPq2oX8awoAN2D/cgCewJcCo= +github.com/lightninglabs/neutrino v0.14.2/go.mod h1:OICUeTCn+4Tu27YRJIpWvvqySxx4oH4vgdP33Sw9RDc= +github.com/lightningnetwork/lightning-onion v1.0.2-0.20220211021909-bb84a1ccb0c5 h1:TkKwqFcQTGYoI+VEqyxA8rxpCin8qDaYX0AfVRinT3k= +github.com/lightningnetwork/lnd v0.15.0-beta h1:smzYjJqL4nGuj4qrAWdikrPzPJ8fcPRFHQ86S2tHR1M= +github.com/lightningnetwork/lnd v0.15.0-beta/go.mod h1:Tm7LZrYeR2JQH1gEOKmd0NTCgjJ1Bnujkx4lcz9b5+A= +github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg= +github.com/lightningnetwork/lnd/clock v1.1.0 h1:/yfVAwtPmdx45aQBoXQImeY7sOIEr7IXlImRMBOZ7GQ= +github.com/lightningnetwork/lnd/clock v1.1.0/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg= +github.com/lightningnetwork/lnd/healthcheck v1.2.2 h1:im+qcpgSuteqRCGeorT9yqVXuLrS6A7/acYzGgarMS4= +github.com/lightningnetwork/lnd/kvdb v1.3.1 h1:gEz3zudNNRrCLEvqRaktYoKwsUblyHX+MKjR0aI3QnM= +github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms= +github.com/lightningnetwork/lnd/queue v1.1.0 h1:YpCJjlIvVxN/R7ww2aNiY8ex7U2fucZDLJ67tI3HFx8= +github.com/lightningnetwork/lnd/queue v1.1.0/go.mod h1:YTkTVZCxz8tAYreH27EO3s8572ODumWrNdYW2E/YKxg= +github.com/lightningnetwork/lnd/ticker v1.0.0/go.mod h1:iaLXJiVgI1sPANIF2qYYUJXjoksPNvGNYowB8aRbpX0= +github.com/lightningnetwork/lnd/ticker v1.1.0 h1:ShoBiRP3pIxZHaETndfQ5kEe+S4NdAY1hiX7YbZ4QE4= +github.com/lightningnetwork/lnd/ticker v1.1.0/go.mod h1:ubqbSVCn6RlE0LazXuBr7/Zi6QT0uQo++OgIRBxQUrk= +github.com/lightningnetwork/lnd/tlv v1.0.2/go.mod h1:fICAfsqk1IOsC1J7G9IdsWX1EqWRMqEDCNxZJSKr9C4= +github.com/lightningnetwork/lnd/tlv v1.0.3 h1:0xBZcPuXagP6f7TY/RnLNR4igE21ov6qUdTr5NyvhhI= +github.com/lightningnetwork/lnd/tlv v1.0.3/go.mod h1:dzR/aZetBri+ZY/fHbwV06fNn/3UID6htQzbHfREFdo= +github.com/lightningnetwork/lnd/tor v1.0.1 h1:A11FrpU0Y//g+fA827W4VnjOeoIvExONdchlLX8wYkA= +github.com/lightningnetwork/lnd/tor v1.0.1/go.mod h1:RDtaAdwfAm+ONuPYwUhNIH1RAvKPv+75lHPOegUcz64= +github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE= +github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/nwaples/rardecode v1.1.2 h1:Cj0yZY6T1Zx1R7AhTbyGSALm44/Mmq+BAPc4B/p/d3M= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pierrec/lz4/v4 v4.1.8 h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs= github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= +github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc= github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw= +go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU= +go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs= +go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek= +go.etcd.io/etcd/pkg/v3 v3.5.0 h1:ntrg6vvKRW26JRmHTE0iNlDgYK6JX3hg/4cD62X0ixk= +go.etcd.io/etcd/raft/v3 v3.5.0 h1:kw2TmO3yFTgE+F0mdKkG7xMxkit2duBDa2Hu6D/HMlw= +go.etcd.io/etcd/server/v3 v3.5.0 h1:jk8D/lwGEDlQU9kZXUFMSANkE22Sg5+mW27ip8xcF9E= +go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 h1:sO4WKdPAudZGKPcpZT4MJn6JaDmpyLrMPDGGyA1SttE= +go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= +go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= +go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= +go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0 h1:c5VRjxCXdQlx1HjzwGdQHzZaVI82b5EbBgOu2ljD92g= +go.opentelemetry.io/otel/sdk/metric v0.20.0 h1:7ao1wpzHRVKf0OQ7GIxiQJA6X7DLX9o14gmVon7mMK8= +go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= +go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= diff --git a/handlers.go b/handlers.go index f7f960f..537d446 100644 --- a/handlers.go +++ b/handlers.go @@ -35,6 +35,11 @@ var upgrader = websocket.Upgrader{ func handleWebsocket(relay Relay) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { + store := relay.Storage() + advancedQuerier, _ := store.(AdvancedQuerier) + advancedDeleter, _ := store.(AdvancedDeleter) + advancedSaver, _ := store.(AdvancedSaver) + conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Warn().Err(err).Msg("failed to upgrade websocket") @@ -111,6 +116,18 @@ func handleWebsocket(relay Relay) func(http.ResponseWriter, *http.Request) { hash := sha256.Sum256(serialized) evt.ID = hex.EncodeToString(hash[:]) + // block too many indexable tags + t := 0 + for _, tag := range evt.Tags { + if len(tag[0]) == 1 { + t++ + } + } + if t > 3 { + notice = "too many indexable tags" + return + } + // check signature (requires the ID to be set) if ok, err := evt.CheckSignature(); err != nil { notice = "signature verification error" @@ -124,21 +141,40 @@ func handleWebsocket(relay Relay) func(http.ResponseWriter, *http.Request) { // event deletion -- nip09 for _, tag := range evt.Tags { if len(tag) >= 2 && tag[0] == "e" { - if err := relay.DeleteEvent(tag[1], evt.PubKey); err != nil { + if advancedDeleter != nil { + advancedDeleter.BeforeDelete(tag[1], evt.PubKey) + } + + if err := store.DeleteEvent(tag[1], evt.PubKey); err != nil { notice = fmt.Sprintf("failed to delete: %s", err.Error()) return } + + if advancedDeleter != nil { + advancedDeleter.AfterDelete(tag[1], evt.PubKey) + } } } return } - err = relay.SaveEvent(&evt) - if err != nil { + if !relay.AcceptEvent(&evt) { + return + } + + if advancedSaver != nil { + advancedSaver.BeforeSave(&evt) + } + + if err := store.SaveEvent(&evt); err != nil { notice = err.Error() return } + if advancedSaver != nil { + advancedSaver.AfterSave(&evt) + } + notifyListeners(&evt) break case "REQ": @@ -159,12 +195,21 @@ func handleWebsocket(relay Relay) func(http.ResponseWriter, *http.Request) { return } - events, err := relay.QueryEvents(&filters[i]) + if advancedQuerier != nil { + advancedQuerier.BeforeQuery(&filters[i]) + } + + events, err := store.QueryEvents(&filters[i]) if err == nil { for _, event := range events { ws.WriteJSON([]interface{}{"EVENT", id, event}) } } + + if advancedQuerier != nil { + advancedQuerier.AfterQuery(&filters[i]) + } + ws.WriteJSON([]interface{}{"EOSE", id}) } diff --git a/interface.go b/interface.go index 37ad03d..a89a06b 100644 --- a/interface.go +++ b/interface.go @@ -10,9 +10,8 @@ var Log = log type Relay interface { Name() string Init() error - SaveEvent(*nostr.Event) error - DeleteEvent(id string, pubkey string) error - QueryEvents(*nostr.Filter) ([]nostr.Event, error) + AcceptEvent(*nostr.Event) bool + Storage() Storage } type Injector interface { @@ -22,3 +21,26 @@ type Injector interface { type Informationer interface { GetNIP11InformationDocument() nip11.RelayInformationDocument } + +type AdvancedQuerier interface { + BeforeQuery(*nostr.Filter) + AfterQuery(*nostr.Filter) +} + +type AdvancedDeleter interface { + BeforeDelete(id string, pubkey string) + AfterDelete(id string, pubkey string) +} + +type AdvancedSaver interface { + BeforeSave(*nostr.Event) + AfterSave(*nostr.Event) +} + +type Storage interface { + Init() error + + QueryEvents(filter *nostr.Filter) (events []nostr.Event, err error) + DeleteEvent(id string, pubkey string) error + SaveEvent(event *nostr.Event) error +} diff --git a/start.go b/start.go index 84b8ad1..295a237 100644 --- a/start.go +++ b/start.go @@ -32,17 +32,23 @@ func Start(relay Relay) { // expose this Log instance so implementations can use it Log = log.With().Str("name", relay.Name()).Logger() + // allow implementations to do initialization stuff + if err := relay.Init(); err != nil { + Log.Fatal().Err(err).Msg("failed to start") + } + + // initialize storage + if err := relay.Storage().Init(); err != nil { + log.Fatal().Err(err).Msg("error initializing storage") + return + } + // catch the websocket call before anything else Router.Path("/").Headers("Upgrade", "websocket").HandlerFunc(handleWebsocket(relay)) // nip-11, relay information Router.Path("/").Headers("Accept", "application/nostr+json").HandlerFunc(handleNIP11(relay)) - // allow implementations to do initialization stuff - if err := relay.Init(); err != nil { - Log.Fatal().Err(err).Msg("failed to start") - } - // wait for events to come from implementations, if this is implemented if inj, ok := relay.(Injector); ok { go func() { diff --git a/storage/postgresql/delete.go b/storage/postgresql/delete.go new file mode 100644 index 0000000..1d8c902 --- /dev/null +++ b/storage/postgresql/delete.go @@ -0,0 +1,6 @@ +package postgresql + +func (b PostgresBackend) DeleteEvent(id string, pubkey string) error { + _, err := b.DB.Exec("DELETE FROM events WHERE id = $1 AND pubkey = $2") + return err +} diff --git a/basic/postgresql.go b/storage/postgresql/init.go similarity index 74% rename from basic/postgresql.go rename to storage/postgresql/init.go index c804347..30d4e80 100644 --- a/basic/postgresql.go +++ b/storage/postgresql/init.go @@ -1,20 +1,23 @@ -package main +package postgresql import ( "github.com/fiatjaf/relayer" "github.com/jmoiron/sqlx" - _ "github.com/lib/pq" + "github.com/jmoiron/sqlx/reflectx" ) -func initDB(dburl string) (*sqlx.DB, error) { - db, err := sqlx.Connect("postgres", dburl) +func (b *PostgresBackend) Init() error { + db, err := sqlx.Connect("postgres", b.DatabaseURL) if err != nil { - return nil, err + return err } - _, err = db.Exec(` + db.Mapper = reflectx.NewMapperFunc("json", sqlx.NameMapper) + b.DB = db + + _, err = b.DB.Exec(` CREATE FUNCTION tags_to_tagvalues(jsonb) RETURNS text[] - AS 'SELECT array_agg(t->>1) FROM (SELECT jsonb_array_elements($1) AS t)s;' + AS 'SELECT array_agg(t->>1) FROM (SELECT jsonb_array_elements($1) AS t)s WHERE length(array_agg(t->>0)) = 1;' LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT; @@ -38,5 +41,5 @@ CREATE INDEX IF NOT EXISTS kindidx ON event (kind); CREATE INDEX IF NOT EXISTS arbitrarytagvalues ON event USING gin (tagvalues); `) relayer.Log.Print(err) - return db, nil + return nil } diff --git a/storage/postgresql/postgresql.go b/storage/postgresql/postgresql.go new file mode 100644 index 0000000..aa55ddc --- /dev/null +++ b/storage/postgresql/postgresql.go @@ -0,0 +1,10 @@ +package postgresql + +import ( + "github.com/jmoiron/sqlx" +) + +type PostgresBackend struct { + *sqlx.DB + DatabaseURL string +} diff --git a/whitelisted/query.go b/storage/postgresql/query.go similarity index 94% rename from whitelisted/query.go rename to storage/postgresql/query.go index e77cf8d..74b73c0 100644 --- a/whitelisted/query.go +++ b/storage/postgresql/query.go @@ -1,4 +1,4 @@ -package main +package postgresql import ( "database/sql" @@ -10,10 +10,10 @@ import ( "time" "github.com/fiatjaf/go-nostr" - "github.com/rs/zerolog/log" + "github.com/fiatjaf/relayer" ) -func (b *ClosedRelay) QueryEvents(filter *nostr.Filter) (events []nostr.Event, err error) { +func (b PostgresBackend) QueryEvents(filter *nostr.Filter) (events []nostr.Event, err error) { var conditions []string var params []any @@ -137,7 +137,9 @@ func (b *ClosedRelay) QueryEvents(filter *nostr.Filter) (events []nostr.Event, e rows, err := b.DB.Query(query, params...) if err != nil && err != sql.ErrNoRows { - log.Warn().Err(err).Interface("filter", filter).Str("query", query). + relayer.Log.Warn().Err(err). + Interface("filter", filter). + Str("query", query). Msg("failed to fetch events") return nil, fmt.Errorf("failed to fetch events: %w", err) } diff --git a/whitelisted/save.go b/storage/postgresql/save.go similarity index 76% rename from whitelisted/save.go rename to storage/postgresql/save.go index bfd8a7f..7381c4e 100644 --- a/whitelisted/save.go +++ b/storage/postgresql/save.go @@ -1,4 +1,4 @@ -package main +package postgresql import ( "encoding/json" @@ -9,16 +9,7 @@ import ( "github.com/fiatjaf/go-nostr" ) -func (b *ClosedRelay) SaveEvent(evt *nostr.Event) error { - // disallow anything from non-authorized pubkeys - for _, pubkey := range b.AuthorizedPubkeys { - if pubkey == evt.PubKey { - goto save - } - } - return fmt.Errorf("event from '%s' not allowed here", evt.PubKey) - -save: +func (b *PostgresBackend) SaveEvent(evt *nostr.Event) error { // react to different kinds of events if evt.Kind == nostr.KindSetMetadata || evt.Kind == nostr.KindContactList || (10000 <= evt.Kind && evt.Kind < 20000) { // delete past events from this user @@ -27,8 +18,6 @@ save: // delete past recommend_server events equal to this one b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`, evt.PubKey, evt.Kind, evt.Content) - } else { - // do not delete any, this is a closed relay so we trust everybody to not spam } // insert diff --git a/whitelisted/README b/whitelisted/README.md similarity index 91% rename from whitelisted/README rename to whitelisted/README.md index 7b0c5a3..d7f035f 100644 --- a/whitelisted/README +++ b/whitelisted/README.md @@ -3,7 +3,7 @@ whitelisted relay - a basic relay implementation based on relayer. - uses postgres, which I think must be over version 12 since it uses generated columns. - - only accepts events from specific pubkeys defined via the environment variable `AUTHORIZED_PUBKEYS` (comma-separated). + - only accepts events from specific pubkeys defined via the environment variable `WHITELIST` (comma-separated). running ------- diff --git a/whitelisted/delete.go b/whitelisted/delete.go deleted file mode 100644 index d9c5c40..0000000 --- a/whitelisted/delete.go +++ /dev/null @@ -1,6 +0,0 @@ -package main - -func (b *ClosedRelay) DeleteEvent(id string, pubkey string) error { - _, err := b.DB.Exec("DELETE FROM events WHERE id = $1 AND pubkey = $2") - return err -} diff --git a/whitelisted/main.go b/whitelisted/main.go index 5419740..e21a5b0 100644 --- a/whitelisted/main.go +++ b/whitelisted/main.go @@ -1,43 +1,59 @@ package main import ( + "encoding/json" "fmt" + "github.com/fiatjaf/go-nostr" "github.com/fiatjaf/relayer" - "github.com/jmoiron/sqlx" - "github.com/jmoiron/sqlx/reflectx" + "github.com/fiatjaf/relayer/storage/postgresql" "github.com/kelseyhightower/envconfig" ) -type ClosedRelay struct { - PostgresDatabase string `envconfig:"POSTGRESQL_DATABASE"` - AuthorizedPubkeys []string `envconfig:"AUTHORIZED_PUBKEYS"` - - DB *sqlx.DB +type Relay struct { + PostgresDatabase string `envconfig:"POSTGRESQL_DATABASE"` + Whitelist []string `envconfig:"WHITELIST"` } -func (b *ClosedRelay) Name() string { - return "ClosedRelay" +func (r *Relay) Name() string { + return "WhitelistedRelay" } -func (b *ClosedRelay) Init() error { - err := envconfig.Process("", b) +func (r *Relay) Storage() relayer.Storage { + return &postgresql.PostgresBackend{DatabaseURL: r.PostgresDatabase} +} + +func (r *Relay) Init() error { + err := envconfig.Process("", r) if err != nil { return fmt.Errorf("couldn't process envconfig: %w", err) } - if db, err := initDB(b.PostgresDatabase); err != nil { - return fmt.Errorf("failed to open database: %w", err) - } else { - db.Mapper = reflectx.NewMapperFunc("json", sqlx.NameMapper) - b.DB = db - } - return nil } -func main() { - var b ClosedRelay +func (r *Relay) AcceptEvent(evt *nostr.Event) bool { + // disallow anything from non-authorized pubkeys + found := false + for _, pubkey := range r.Whitelist { + if pubkey == evt.PubKey { + found = true + break + } + } + if !found { + return false + } - relayer.Start(&b) + // block events that are too large + jsonb, _ := json.Marshal(evt) + if len(jsonb) > 100000 { + return false + } + + return true +} + +func main() { + relayer.Start(&Relay{}) } diff --git a/whitelisted/postgresql.go b/whitelisted/postgresql.go deleted file mode 100644 index c804347..0000000 --- a/whitelisted/postgresql.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "github.com/fiatjaf/relayer" - "github.com/jmoiron/sqlx" - _ "github.com/lib/pq" -) - -func initDB(dburl string) (*sqlx.DB, error) { - db, err := sqlx.Connect("postgres", dburl) - if err != nil { - return nil, err - } - - _, err = db.Exec(` -CREATE FUNCTION tags_to_tagvalues(jsonb) RETURNS text[] - AS 'SELECT array_agg(t->>1) FROM (SELECT jsonb_array_elements($1) AS t)s;' - LANGUAGE SQL - IMMUTABLE - RETURNS NULL ON NULL INPUT; - -CREATE TABLE IF NOT EXISTS event ( - id text NOT NULL, - pubkey text NOT NULL, - created_at integer NOT NULL, - kind integer NOT NULL, - tags jsonb NOT NULL, - content text NOT NULL, - sig text NOT NULL, - - tagvalues text[] GENERATED ALWAYS AS (tags_to_tagvalues(tags)) STORED -); - -CREATE UNIQUE INDEX IF NOT EXISTS ididx ON event USING btree (id text_pattern_ops); -CREATE INDEX IF NOT EXISTS pubkeyprefix ON event USING btree (pubkey text_pattern_ops); -CREATE INDEX IF NOT EXISTS timeidx ON event (created_at); -CREATE INDEX IF NOT EXISTS kindidx ON event (kind); -CREATE INDEX IF NOT EXISTS arbitrarytagvalues ON event USING gin (tagvalues); - `) - relayer.Log.Print(err) - return db, nil -}