Skip to content
Open
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
2 changes: 1 addition & 1 deletion .justfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ install-dependencies:

# Start services with docker compose
[working-directory: 'docker']
docker-up $COMPOSE_PROFILES='mempool':
docker-up $COMPOSE_PROFILES='mempool-btc':
#!/usr/bin/env bash
set -euo pipefail
IFS=',' read -ra profiles <<< "$COMPOSE_PROFILES"
Expand Down
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,21 @@ npm install --workspaces
2. Start services with docker compose

```bash
cd server-backend/dev
docker compose up
cd docker
docker compose up <profile>
```

or

```bash
just docker-up
```

3. Initialize blockchain and lightning nodes

```bash
server-backend/dev/nodes-setup.sh
cd docker
nodes-setup.sh
```

4. Build shared module
Expand Down Expand Up @@ -60,7 +67,7 @@ npm run start:dev
By sourcing [`server-backend/dev/dev-aliases.sh`](server-backend/dev/dev-aliases.sh) you can get access to some useful commands, e.g.:

```bash
source server-backend/dev/dev-aliases.sh
source docker/dev-aliases.sh
Comment on lines 67 to +70
# mine N blocks
40swap-bitcoin-cli -generate $N
# pay lightning invoice from user node
Expand Down
108 changes: 55 additions & 53 deletions daemon/.golangci.yml
Original file line number Diff line number Diff line change
@@ -1,64 +1,66 @@
run:
# timeout for analysis
timeout: 10m

issues:
# Skip autogenerated files for mobile and gRPC as well as copied code for
# internal use.
exclude-files:
- "\\.pb\\.go$"
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gosec
# files with mock in the name are excluded from gosec
- path: .*mock.*
linters:
- gosec

version: "2"
linters:
disable-all: true
default: none
enable:
# enabled by default
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unparam
- bodyclose

# style
- dupl
- errcheck
- errname
- goimports
- errorlint
- exhaustive
- gosec
- govet
- ineffassign
- nlreturn
- noctx
- revive
- staticcheck
- tagliatelle
- unparam
- whitespace

# bugs
- errorlint
- gosec
- noctx

linters-settings:
gofmt:
rewrite-rules:
- pattern: "interface{}"
replacement: "any"
- pattern: "a[b:len(a)]"
replacement: "a[b:]"

tagliatelle:
case:
settings:
revive:
rules:
json: camel


revive:
- name: duplicated-imports
severity: warning
disabled: false
tagliatelle:
case:
rules:
json: camel
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- name: duplicated-imports
severity: warning
disabled: false
- linters:
- gosec
path: _test\.go
- linters:
- gosec
path: .*mock.*
paths:
- \.pb\.go$
- third_party$
- builtin$
- examples$
formatters:
enable:
- goimports
settings:
gofmt:
rewrite-rules:
- pattern: interface{}
replacement: any
- pattern: a[b:len(a)]
replacement: a[b:]
exclusions:
generated: lax
paths:
- \.pb\.go$
- third_party$
- builtin$
- examples$
38 changes: 37 additions & 1 deletion daemon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,40 @@ The 40swap daemon (40swapd) interacts with the lightning node to manage the swap

## Docs

You can configure the 40swap daemon using environment variables or command line arguments. Check `40swapd -h` for more information.
You can configure the 40swap daemon using environment variables or command line arguments. Check `40swapd -h` for more information.

# Local dev environment

## Pre-requisites
go 1.24.1 or later

## Instructions

1. Install all the dependencies from the root folder

```bash
go mod tidy
```

2. Run the daemon

```bash
just run-daemon
```

3. Create a swap in

```bash
just user-lncli addinvoice 200000 # Copy the payreq
just run swap in --payreq <payreq>

just sendtoaddress <claim address> <amount_btc> # the amount in the response of the swap in request
just generate 3
```

4. Create a swap out

```bash
just run swap out --address bcrt1q94gs370gfjut9d75ss3j7m8l7m3phs06nlqd8n --amt 200000
just generate 6
```
2 changes: 1 addition & 1 deletion daemon/bitcoin/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ func BuildPSBTFromOutpoint(spendingTxHex *wire.MsgTx, lockScript string, outpoin
// Create the output script from the address
outputScript, err := txscript.PayToAddrScript(destinationAddr)
if err != nil {
return nil, fmt.Errorf("Failed to create output script: %w", err)
return nil, fmt.Errorf("failed to create output script: %w", err)
}

txOut := wire.NewTxOut(amount, outputScript)
Expand Down
6 changes: 1 addition & 5 deletions daemon/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func main() {
return err
}

db, closeDb, err := database.New(
db, closeDb, err := database.New(ctx,
c.String("db-user"),
c.String("db-password"),
c.String("db-name"),
Expand Down Expand Up @@ -587,10 +587,6 @@ var bitcoin = cli.BoolFlag{
Name: "bitcoin",
Usage: "Use Bitcoin chain",
}
var liquid = cli.BoolFlag{
Name: "liquid",
Usage: "Use Liquid chain",
}

// Ports and hosts
var grpcPort = cli.IntFlag{
Expand Down
2 changes: 1 addition & 1 deletion daemon/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func Start(ctx context.Context, server *rpc.Server, db Repository, swaps swaps.C
}

go func() {
err := server.ListenAndServe()
err := server.ListenAndServe(ctx)
if err != nil {
log.Fatalf("couldn't start server: %v", err)
}
Expand Down
12 changes: 6 additions & 6 deletions daemon/database/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func main() {
Name: "migrate",
Usage: "Migrate the database",
Action: func(ctx context.Context, cmd *cli.Command) error {
db, closeDb, err := StartDatabase(cmd)
db, closeDb, err := StartDatabase(ctx, cmd)
if err != nil {
return fmt.Errorf("❌ Could not connect to database: %w", err)
}
Expand All @@ -86,7 +86,7 @@ func main() {
Name: "rollback",
Usage: "Rollback the database",
Action: func(ctx context.Context, cmd *cli.Command) error {
db, closeDb, err := StartDatabase(cmd)
db, closeDb, err := StartDatabase(ctx, cmd)
if err != nil {
return fmt.Errorf("❌ Could not connect to database: %w", err)
}
Expand All @@ -108,7 +108,7 @@ func main() {
Name: "reset",
Usage: "Reset the database",
Action: func(ctx context.Context, cmd *cli.Command) error {
db, closeDb, err := StartDatabase(cmd)
db, closeDb, err := StartDatabase(ctx, cmd)
if err != nil {
return fmt.Errorf("❌ Could not connect to database: %w", err)
}
Expand Down Expand Up @@ -137,7 +137,7 @@ func main() {
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
db, closeDb, err := StartDatabase(cmd)
db, closeDb, err := StartDatabase(ctx, cmd)
if err != nil {
return fmt.Errorf("❌ Could not connect to database: %w", err)
}
Expand Down Expand Up @@ -176,13 +176,13 @@ func main() {
}
}

func StartDatabase(cmd *cli.Command) (*database.Database, func() error, error) {
func StartDatabase(ctx context.Context, cmd *cli.Command) (*database.Database, func() error, error) {
port, err := validatePort(cmd.Int("db-port"))
if err != nil {
return nil, nil, err
}

db, closeDb, err := database.New(
db, closeDb, err := database.New(ctx,
cmd.String("db-user"),
cmd.String("db-password"),
cmd.String("db-name"),
Expand Down
27 changes: 14 additions & 13 deletions daemon/database/database.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package database

import (
"context"
"errors"
"fmt"
"os/exec"
Expand Down Expand Up @@ -40,7 +41,7 @@ type Database struct {
query *gen.Query
}

func New(username, password, database string, port uint32, dataPath, host string, keepAlive bool) (*Database, func() error, error) {
func New(ctx context.Context, username, password, database string, port uint32, dataPath, host string, keepAlive bool) (*Database, func() error, error) {
models.RegisterPreimageSerializer()

db := Database{
Expand All @@ -66,18 +67,18 @@ func New(username, password, database string, port uint32, dataPath, host string

close = func() error {
if err := db.close(); err != nil {
return fmt.Errorf("Could not close database connection: %w", err)
return fmt.Errorf("could not close database connection: %w", err)
}

if !keepAlive {
if err := postgres.Stop(); err != nil {
if errors.Is(err, embeddedpostgres.ErrServerNotStarted) && isPostgresRunning(port) {
killPostgres(port)
if errors.Is(err, embeddedpostgres.ErrServerNotStarted) && isPostgresRunning(ctx, port) {
killPostgres(ctx, port)

Comment on lines 73 to 77
return nil
}

return fmt.Errorf("Could not stop embedded database: %w", err)
return fmt.Errorf("could not stop embedded database: %w", err)
}
log.Info("✅ DB stopped")
}
Expand Down Expand Up @@ -118,7 +119,7 @@ func (d *Database) GetConnectionURL() string {
func (d *Database) getGorm() (*gorm.DB, error) {
gormDB, err := gorm.Open(postgres.Open(d.GetConnectionURL()), &gorm.Config{})
if err != nil {
return nil, fmt.Errorf("Could not connect GORM: %w", err)
return nil, fmt.Errorf("could not connect GORM: %w", err)
}

log.Info("✅ DB connected")
Expand Down Expand Up @@ -160,11 +161,11 @@ func (d *Database) Generate(path string) error {
func (d *Database) close() error {
db, err := d.orm.DB()
if err != nil {
return fmt.Errorf("Could not get database connection: %w", err)
return fmt.Errorf("could not get database connection: %w", err)
}
Comment on lines 161 to 165

if err := db.Close(); err != nil {
return fmt.Errorf("Could not close database connection: %w", err)
return fmt.Errorf("could not close database connection: %w", err)
}

return nil
Expand Down Expand Up @@ -196,27 +197,27 @@ func newEmbeddedDatabase(username, password, database string, port uint32, dataP
return postgres, nil
}

func isPostgresRunning(port uint32) bool {
func isPostgresRunning(ctx context.Context, port uint32) bool {
if port < 1 || port > 65535 {
return false
}
//nolint:gosec
out, err := exec.Command("lsof", "-i", fmt.Sprintf(":%d", port), "-t").Output()
out, err := exec.CommandContext(ctx, "lsof", "-i", fmt.Sprintf(":%d", port), "-t").Output()
if err != nil {
return false
}

return len(out) > 0
}

func killPostgres(port uint32) {
func killPostgres(ctx context.Context, port uint32) {
if port < 1 || port > 65535 {
return
}
//nolint:gosec
out, err := exec.Command("lsof", "-i", fmt.Sprintf(":%d", port), "-t").Output()
out, err := exec.CommandContext(ctx, "lsof", "-i", fmt.Sprintf(":%d", port), "-t").Output()
if err == nil {
pid := strings.TrimSpace(string(out))
_ = exec.Command("kill", "-9", pid).Run()
_ = exec.CommandContext(ctx, "kill", "-9", pid).Run()
Comment thread
RodriFS marked this conversation as resolved.
}
Comment on lines +218 to 222
}
Loading
Loading