Cleanup & Add config and launcher (#57)

* Fixes

* Fixes to domain layer:
* Add Leaf bool field to know to fix the returned list of leaves
* Add non-persisted UnsignedForfeitTxs to RoundFinalizationStarted
* Store only error msg when round fails instead of full error

* Fix wallet interface:
* Add Close() to close conn with wallet
* Add GetAsset() to fix missing asset err when calling Transfer()

* Fix gocron scheduler to correctly run/build the project

* Fix badger repo implementation:
* Fix datadirs of projection stores
* Return error if current round not found
* Fix round event deserialization

* Fix TxBuilder interface & dummy impl:
* Pass asp pubkey as arg of the defined functions
* Fix connectorsToInputArgs to return the right number of ins
* Fix getTxid() to return the id of an hex encoded tx too
* Fix createConnectors() to return a tx if there's only 1 connector
* Add leaf bool field to psetWithLevel in case a leaf is not in the last level
* Fix node's isLeaf() check
* Move to hex encoded pubkeys instead of ark encoded

* Fix app layer:
* Add Start() and Stop() to the interface & Expect raw pubkeys instead of strings as args
* Source & cache pubkey from wallet at startup
* Drop usage of scheduler and schedule next task based on occurred round events
* Increase verbosity
* Use hex instead of ark encoding to store receveirs' pubkeys
* Lower faucet amount from 100k to 10k sats in total
* Fix finalizeRound() to persist round events even if it failed
* Add view() to forfeitTxMap to enrich RoundFinalizationEvent with unsigned forfeit txs

* Add app config

* Fix interface layer:
* Remove repo manager from handler factory
* Fix GetEventStream to forward events to stream once they arrive from app layer
* Return missing unsigned forfeit txs in RoundFinalizationEvent
* Fix extracting user pubkey from address
* Add log interceptors
* Add config struct
* Add factory
* Clean interface

* Add config and launcher

* Tidy deps & Set defaut round interval to 30secs for dev mode
This commit is contained in:
Pietralberto Mazza
2023-12-12 14:55:22 +01:00
committed by GitHub
parent e5df6cfc39
commit 3985bd4e14
38 changed files with 773 additions and 334 deletions

View File

@@ -34,6 +34,7 @@ lint:
run: clean run: clean
@echo "Running arkd in dev mode..." @echo "Running arkd in dev mode..."
@export ARK_WALLET_ADDR=localhost:18000; \ @export ARK_WALLET_ADDR=localhost:18000; \
export ARK_ROUND_INTERVAL=30; \
go run ./cmd/arkd go run ./cmd/arkd
## test: runs unit and component tests ## test: runs unit and component tests

View File

@@ -5,7 +5,9 @@ import (
"os/signal" "os/signal"
"syscall" "syscall"
service_interface "github.com/ark-network/ark/internal/interface" appconfig "github.com/ark-network/ark/internal/app-config"
"github.com/ark-network/ark/internal/config"
grpcservice "github.com/ark-network/ark/internal/interface/grpc"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@@ -17,7 +19,27 @@ var (
) )
func main() { func main() {
svc, err := service_interface.NewService(service_interface.Options{}) // TODO populate options cfg, err := config.LoadConfig()
if err != nil {
log.WithError(err).Fatal("invalid config")
}
log.SetLevel(log.Level(cfg.LogLevel))
svcConfig := grpcservice.Config{
Port: cfg.Port,
NoTLS: cfg.NoTLS,
}
appConfig := &appconfig.Config{
DbType: cfg.DbType,
DbDir: cfg.DbDir,
RoundInterval: cfg.RoundInterval,
Network: cfg.Network,
SchedulerType: cfg.SchedulerType,
TxBuilderType: cfg.TxBuilderType,
WalletAddr: cfg.WalletAddr,
}
svc, err := grpcservice.NewService(svcConfig, appConfig)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@@ -6,11 +6,12 @@ replace github.com/ark-network/ark/common => ../common
require ( require (
github.com/ark-network/ark/common v0.0.0-00010101000000-000000000000 github.com/ark-network/ark/common v0.0.0-00010101000000-000000000000
github.com/btcsuite/btcd/btcec/v2 v2.2.0
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0
github.com/dgraph-io/badger/v4 v4.1.0 github.com/dgraph-io/badger/v4 v4.1.0
github.com/go-co-op/gocron v1.36.0 github.com/go-co-op/gocron v1.36.0
github.com/gogo/protobuf v1.3.2
github.com/google/uuid v1.4.0 github.com/google/uuid v1.4.0
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spf13/viper v1.17.0 github.com/spf13/viper v1.17.0
@@ -23,41 +24,34 @@ require (
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
) )
require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.1.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v23.5.9+incompatible // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect
)
require ( require (
github.com/btcsuite/btcd v0.23.1 // indirect github.com/btcsuite/btcd v0.23.1 // indirect
github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/btcutil v1.1.3
github.com/btcsuite/btcd/btcutil/psbt v1.1.4 // indirect github.com/btcsuite/btcd/btcutil/psbt v1.1.4 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/golang/glog v1.1.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v23.5.9+incompatible // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
@@ -66,12 +60,16 @@ require (
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 // indirect github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@@ -40,6 +40,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= 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.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
@@ -125,6 +126,9 @@ github.com/go-co-op/gocron v1.36.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISk
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -201,6 +205,8 @@ github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -223,6 +229,7 @@ github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -249,10 +256,12 @@ github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 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.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
@@ -274,6 +283,7 @@ github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9c
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
@@ -293,6 +303,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -336,10 +347,14 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -459,6 +474,7 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -495,6 +511,7 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -538,6 +555,7 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -625,6 +643,7 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
@@ -692,8 +711,10 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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.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.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -0,0 +1,170 @@
package appconfig
import (
"fmt"
"strings"
"github.com/ark-network/ark/common"
"github.com/ark-network/ark/internal/core/application"
"github.com/ark-network/ark/internal/core/ports"
"github.com/ark-network/ark/internal/infrastructure/db"
oceanwallet "github.com/ark-network/ark/internal/infrastructure/ocean-wallet"
txbuilder "github.com/ark-network/ark/internal/infrastructure/tx-builder/dummy"
log "github.com/sirupsen/logrus"
"github.com/vulpemventures/go-elements/network"
)
var (
supportedDbs = supportedType{
"badger": {},
}
supportedSchedulers = supportedType{
"gocron": {},
}
supportedTxBuilders = supportedType{
"dummy": {},
}
)
type Config struct {
DbType string
DbDir string
RoundInterval int64
Network common.Network
SchedulerType string
TxBuilderType string
WalletAddr string
repo ports.RepoManager
svc application.Service
wallet ports.WalletService
txBuilder ports.TxBuilder
}
func (c *Config) Validate() error {
if !supportedDbs.supports(c.DbType) {
return fmt.Errorf("db type not supported, please select one of: %s", supportedDbs)
}
if !supportedSchedulers.supports(c.SchedulerType) {
return fmt.Errorf("scheduler type not supported, please select one of: %s", supportedSchedulers)
}
if !supportedTxBuilders.supports(c.TxBuilderType) {
return fmt.Errorf("tx builder type not supported, please select one of: %s", supportedTxBuilders)
}
if c.RoundInterval < 5 {
return fmt.Errorf("invalid round interval, must be at least 5 seconds")
}
if c.Network.Name != "liquid" && c.Network.Name != "testnet" {
return fmt.Errorf("invalid network, must be either liquid or testnet")
}
if len(c.WalletAddr) <= 0 {
return fmt.Errorf("missing onchain wallet address")
}
if err := c.repoManager(); err != nil {
return err
}
if err := c.walletService(); err != nil {
return fmt.Errorf("failed to connect to wallet: %s", err)
}
if err := c.txBuilderService(); err != nil {
return err
}
if err := c.appService(); err != nil {
return err
}
return nil
}
func (c *Config) AppService() application.Service {
return c.svc
}
func (c *Config) repoManager() error {
var svc ports.RepoManager
var err error
switch c.DbType {
case "badger":
logger := log.New()
svc, err = db.NewService(db.ServiceConfig{
EventStoreType: c.DbType,
RoundStoreType: c.DbType,
VtxoStoreType: c.DbType,
EventStoreConfig: []interface{}{c.DbDir, logger},
RoundStoreConfig: []interface{}{c.DbDir, logger},
VtxoStoreConfig: []interface{}{c.DbDir, logger},
})
default:
return fmt.Errorf("unknown db type")
}
if err != nil {
return err
}
c.repo = svc
return nil
}
func (c *Config) walletService() error {
svc, err := oceanwallet.NewService(c.WalletAddr)
if err != nil {
return err
}
c.wallet = svc
return nil
}
func (c *Config) txBuilderService() error {
var svc ports.TxBuilder
var err error
net := c.mainChain()
switch c.TxBuilderType {
case "dummy":
svc = txbuilder.NewTxBuilder(net)
default:
err = fmt.Errorf("unknown db type")
}
if err != nil {
return err
}
c.txBuilder = svc
return nil
}
func (c *Config) appService() error {
net := c.mainChain()
svc, err := application.NewService(
c.RoundInterval, c.Network, net, c.wallet, c.repo, c.txBuilder,
)
if err != nil {
return err
}
c.svc = svc
return nil
}
func (c *Config) mainChain() network.Network {
net := network.Liquid
if c.Network.Name != "mainnet" {
net = network.Testnet
}
return net
}
type supportedType map[string]struct{}
func (t supportedType) String() string {
types := make([]string, 0, len(t))
for tt := range t {
types = append(types, tt)
}
return strings.Join(types, " | ")
}
func (t supportedType) supports(typeStr string) bool {
_, ok := t[typeStr]
return ok
}

View File

@@ -3,6 +3,8 @@ package config
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"strings"
common "github.com/ark-network/ark/common" common "github.com/ark-network/ark/common"
"github.com/spf13/viper" "github.com/spf13/viper"
@@ -11,15 +13,37 @@ import (
type Config struct { type Config struct {
WalletAddr string WalletAddr string
RoundInterval int64 RoundInterval int64
Port uint32
DbType string
DbDir string
SchedulerType string
TxBuilderType string
NoTLS bool
Network common.Network
LogLevel int
} }
var ( var (
Datadir = "DATADIR" Datadir = "DATADIR"
WalletAddr = "WALLET_ADDR" WalletAddr = "WALLET_ADDR"
RoundInterval = "ROUND_INTERVAL" RoundInterval = "ROUND_INTERVAL"
Port = "PORT"
DbType = "DB_TYPE"
SchedulerType = "SCHEDULER_TYPE"
TxBuilderType = "TX_BUILDER_TYPE"
Insecure = "INSECURE"
LogLevel = "LOG_LEVEL"
Network = "NETWORK"
defaultDatadir = common.AppDataDir("arkd", false) defaultDatadir = common.AppDataDir("arkd", false)
defaultRoundInterval = 60 defaultRoundInterval = 60
defaultPort = 6000
defaultDbType = "badger"
defaultSchedulerType = "gocron"
defaultTxBuilderType = "dummy"
defaultInsecure = true
defaultNetwork = "testnet"
defaultLogLevel = 5
) )
func LoadConfig() (*Config, error) { func LoadConfig() (*Config, error) {
@@ -28,30 +52,35 @@ func LoadConfig() (*Config, error) {
viper.SetDefault(Datadir, defaultDatadir) viper.SetDefault(Datadir, defaultDatadir)
viper.SetDefault(RoundInterval, defaultRoundInterval) viper.SetDefault(RoundInterval, defaultRoundInterval)
viper.SetDefault(Port, defaultPort)
viper.SetDefault(DbType, defaultDbType)
viper.SetDefault(SchedulerType, defaultSchedulerType)
viper.SetDefault(TxBuilderType, defaultTxBuilderType)
viper.SetDefault(Insecure, defaultInsecure)
viper.SetDefault(LogLevel, defaultLogLevel)
viper.SetDefault(Network, defaultNetwork)
net, err := getNetwork()
if err != nil {
return nil, err
}
if err := initDatadir(); err != nil { if err := initDatadir(); err != nil {
return nil, fmt.Errorf("error while creating datadir: %s", err) return nil, fmt.Errorf("error while creating datadir: %s", err)
} }
cfg := &Config{ return &Config{
WalletAddr: viper.GetString(WalletAddr), WalletAddr: viper.GetString(WalletAddr),
RoundInterval: viper.GetInt64(RoundInterval), RoundInterval: viper.GetInt64(RoundInterval),
} Port: viper.GetUint32(Port),
DbType: viper.GetString(DbType),
if err := cfg.validate(); err != nil { SchedulerType: viper.GetString(SchedulerType),
return nil, err TxBuilderType: viper.GetString(TxBuilderType),
} NoTLS: viper.GetBool(Insecure),
return cfg, nil DbDir: filepath.Join(viper.GetString(Datadir), "db"),
} LogLevel: viper.GetInt(LogLevel),
Network: net,
func (c *Config) validate() error { }, nil
if len(c.WalletAddr) <= 0 {
return fmt.Errorf("missing wallet address")
}
if c.RoundInterval < 5 {
return fmt.Errorf("round interval must be at least 5 seconds")
}
return nil
} }
func initDatadir() error { func initDatadir() error {
@@ -65,3 +94,14 @@ func makeDirectoryIfNotExists(path string) error {
} }
return nil return nil
} }
func getNetwork() (common.Network, error) {
switch strings.ToLower(viper.GetString(Network)) {
case "mainnet":
return common.MainNet, nil
case "testnet":
return common.TestNet, nil
default:
return common.Network{}, fmt.Errorf("unknown network")
}
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/ark-network/ark/common" "github.com/ark-network/ark/common"
"github.com/ark-network/ark/internal/core/domain" "github.com/ark-network/ark/internal/core/domain"
"github.com/ark-network/ark/internal/core/ports" "github.com/ark-network/ark/internal/core/ports"
"github.com/btcsuite/btcd/btcec/v2" "github.com/decred/dcrd/dcrec/secp256k1/v4"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/vulpemventures/go-elements/address" "github.com/vulpemventures/go-elements/address"
"github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/network"
@@ -28,14 +28,16 @@ var (
) )
type Service interface { type Service interface {
Start() error
Stop()
SpendVtxos(ctx context.Context, inputs []domain.VtxoKey) (string, error) SpendVtxos(ctx context.Context, inputs []domain.VtxoKey) (string, error)
ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) error
SignVtxos(ctx context.Context, forfeitTxs []string) error SignVtxos(ctx context.Context, forfeitTxs []string) error
FaucetVtxos(ctx context.Context, pubkey string) error FaucetVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) error
GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.Round, error) GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.Round, error)
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
UpdatePaymentStatus(ctx context.Context, id string) error UpdatePaymentStatus(ctx context.Context, id string) error
ListVtxos(ctx context.Context, pubkey string) ([]domain.Vtxo, error) ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, error)
GetPubkey(ctx context.Context) (string, error) GetPubkey(ctx context.Context) (string, error)
} }
@@ -43,10 +45,9 @@ type service struct {
roundInterval int64 roundInterval int64
network common.Network network common.Network
onchainNework network.Network onchainNework network.Network
pubkey string pubkey *secp256k1.PublicKey
wallet ports.WalletService wallet ports.WalletService
scheduler ports.SchedulerService
repoManager ports.RepoManager repoManager ports.RepoManager
builder ports.TxBuilder builder ports.TxBuilder
paymentRequests *paymentsMap paymentRequests *paymentsMap
@@ -57,16 +58,18 @@ type service struct {
func NewService( func NewService(
interval int64, network common.Network, onchainNetwork network.Network, interval int64, network common.Network, onchainNetwork network.Network,
walletSvc ports.WalletService, schedulerSvc ports.SchedulerService, walletSvc ports.WalletService, repoManager ports.RepoManager, builder ports.TxBuilder,
repoManager ports.RepoManager, builder ports.TxBuilder, ) (Service, error) {
) Service {
pubkey := ""
eventsCh := make(chan domain.RoundEvent) eventsCh := make(chan domain.RoundEvent)
paymentRequests := newPaymentsMap(nil) paymentRequests := newPaymentsMap(nil)
forfeitTxs := newForfeitTxsMap() forfeitTxs := newForfeitTxsMap()
pubkey, err := walletSvc.GetPubkey(context.Background())
if err != nil {
return nil, fmt.Errorf("failed to fetch pubkey: %s", err)
}
svc := &service{ svc := &service{
interval, network, onchainNetwork, pubkey, interval, network, onchainNetwork, pubkey,
walletSvc, schedulerSvc, repoManager, builder, paymentRequests, forfeitTxs, walletSvc, repoManager, builder, paymentRequests, forfeitTxs,
eventsCh, eventsCh,
} }
repoManager.RegisterEventsHandler( repoManager.RegisterEventsHandler(
@@ -75,13 +78,21 @@ func NewService(
svc.propagateEvents(round) svc.propagateEvents(round)
}, },
) )
return svc return svc, nil
} }
func (s *service) Start() error { func (s *service) Start() error {
log.Debug("starting app service")
return s.start() return s.start()
} }
func (s *service) Stop() {
s.wallet.Close()
log.Debug("closed connection to wallet")
s.repoManager.Close()
log.Debug("closed connection to db")
}
func (s *service) SpendVtxos(ctx context.Context, inputs []domain.VtxoKey) (string, error) { func (s *service) SpendVtxos(ctx context.Context, inputs []domain.VtxoKey) (string, error) {
vtxos, err := s.repoManager.Vtxos().GetVtxos(ctx, inputs) vtxos, err := s.repoManager.Vtxos().GetVtxos(ctx, inputs)
if err != nil { if err != nil {
@@ -120,13 +131,15 @@ func (s *service) UpdatePaymentStatus(_ context.Context, id string) error {
return s.paymentRequests.updatePingTimestamp(id) return s.paymentRequests.updatePingTimestamp(id)
} }
func (s *service) FaucetVtxos(ctx context.Context, pubkey string) error { func (s *service) FaucetVtxos(ctx context.Context, userPubkey *secp256k1.PublicKey) error {
pubkey := hex.EncodeToString(userPubkey.SerializeCompressed())
payment, err := domain.NewPayment([]domain.Vtxo{ payment, err := domain.NewPayment([]domain.Vtxo{
{ {
VtxoKey: faucetVtxo, VtxoKey: faucetVtxo,
Receiver: domain.Receiver{ Receiver: domain.Receiver{
Pubkey: pubkey, Pubkey: pubkey,
Amount: 100000, Amount: 10000,
}, },
}, },
}) })
@@ -135,16 +148,16 @@ func (s *service) FaucetVtxos(ctx context.Context, pubkey string) error {
} }
if err := payment.AddReceivers([]domain.Receiver{ if err := payment.AddReceivers([]domain.Receiver{
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
{Pubkey: pubkey, Amount: 10000}, {Pubkey: pubkey, Amount: 1000},
}); err != nil { }); err != nil {
return err return err
} }
@@ -162,8 +175,9 @@ func (s *service) SignVtxos(ctx context.Context, forfeitTxs []string) error {
return nil return nil
} }
func (s *service) ListVtxos(ctx context.Context, pubkey string) ([]domain.Vtxo, error) { func (s *service) ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, error) {
return s.repoManager.Vtxos().GetSpendableVtxosWithPubkey(ctx, pubkey) pk := hex.EncodeToString(pubkey.SerializeCompressed())
return s.repoManager.Vtxos().GetSpendableVtxosWithPubkey(ctx, pk)
} }
func (s *service) GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent { func (s *service) GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent {
@@ -175,36 +189,16 @@ func (s *service) GetRoundByTxid(ctx context.Context, poolTxid string) (*domain.
} }
func (s *service) GetPubkey(ctx context.Context) (string, error) { func (s *service) GetPubkey(ctx context.Context) (string, error) {
if s.pubkey == "" { pubkey, err := common.EncodePubKey(s.network.PubKey, s.pubkey)
pubkey, err := s.wallet.GetPubkey(ctx)
if err != nil { if err != nil {
return "", err return "", err
} }
serializedPubkey, err := common.EncodePubKey(s.network.PubKey, pubkey) return pubkey, nil
if err != nil {
return "", err
}
s.pubkey = serializedPubkey
}
return s.pubkey, nil
} }
func (s *service) start() error { func (s *service) start() error {
startImmediately := true s.startRound()
finalizationInterval := int64(s.roundInterval / 2) return nil
if err := s.scheduler.ScheduleTask(
s.roundInterval, startImmediately, s.startRound,
); err != nil {
return err
}
if err := s.scheduler.ScheduleTask(
finalizationInterval, !startImmediately, s.startFinalization,
); err != nil {
return err
}
return s.scheduler.ScheduleTask(
s.roundInterval-1, !startImmediately, s.finalizeRound,
)
} }
func (s *service) startRound() { func (s *service) startRound() {
@@ -217,6 +211,11 @@ func (s *service) startRound() {
return return
} }
defer func() {
time.Sleep(time.Duration(s.roundInterval/2) * time.Second)
s.startFinalization()
}()
log.Debugf("started registration stage for new round: %s", round.Id) log.Debugf("started registration stage for new round: %s", round.Id)
} }
@@ -227,6 +226,16 @@ func (s *service) startFinalization() {
log.WithError(err).Warn("failed to retrieve current round") log.WithError(err).Warn("failed to retrieve current round")
return return
} }
defer func() {
if round.IsFailed() {
s.startRound()
return
}
time.Sleep(time.Duration((s.roundInterval/2)-1) * time.Second)
s.finalizeRound()
}()
if round.IsFailed() { if round.IsFailed() {
return return
} }
@@ -251,29 +260,33 @@ func (s *service) startFinalization() {
num = paymentsThreshold num = paymentsThreshold
} }
payments := s.paymentRequests.pop(num) payments := s.paymentRequests.pop(num)
changes, _ = round.RegisterPayments(payments) changes, err = round.RegisterPayments(payments)
if err != nil {
changes = round.Fail(fmt.Errorf("failed to register payments: %s", err))
log.WithError(err).Warn("failed to register payments")
return
}
signedPoolTx, err := s.builder.BuildPoolTx(s.wallet, payments) signedPoolTx, err := s.builder.BuildPoolTx(s.pubkey, s.wallet, payments)
if err != nil { if err != nil {
changes = round.Fail(fmt.Errorf("failed to create pool tx: %s", err)) changes = round.Fail(fmt.Errorf("failed to create pool tx: %s", err))
log.WithError(err).Warn("failed to create pool tx") log.WithError(err).Warn("failed to create pool tx")
return return
} }
tree, err := s.builder.BuildCongestionTree(signedPoolTx, payments) tree, err := s.builder.BuildCongestionTree(s.pubkey, signedPoolTx, payments)
if err != nil { if err != nil {
changes = round.Fail(fmt.Errorf("failed to create congestion tree: %s", err)) changes = round.Fail(fmt.Errorf("failed to create congestion tree: %s", err))
log.WithError(err).Warn("failed to create congestion tree") log.WithError(err).Warn("failed to create congestion tree")
return return
} }
connectors, forfeitTxs, err := s.builder.BuildForfeitTxs(signedPoolTx, payments) connectors, forfeitTxs, err := s.builder.BuildForfeitTxs(s.pubkey, signedPoolTx, payments)
if err != nil { if err != nil {
changes = round.Fail(fmt.Errorf("failed to create connectors and forfeit txs: %s", err)) changes = round.Fail(fmt.Errorf("failed to create connectors and forfeit txs: %s", err))
log.WithError(err).Warn("failed to create connectors and forfeit txs") log.WithError(err).Warn("failed to create connectors and forfeit txs")
return return
} }
events, _ := round.StartFinalization(connectors, tree, signedPoolTx) events, _ := round.StartFinalization(connectors, tree, signedPoolTx)
changes = append(changes, events...) changes = append(changes, events...)
@@ -283,6 +296,8 @@ func (s *service) startFinalization() {
} }
func (s *service) finalizeRound() { func (s *service) finalizeRound() {
defer s.startRound()
ctx := context.Background() ctx := context.Background()
round, err := s.repoManager.Rounds().GetCurrentRound(ctx) round, err := s.repoManager.Rounds().GetCurrentRound(ctx)
if err != nil { if err != nil {
@@ -293,27 +308,30 @@ func (s *service) finalizeRound() {
return return
} }
var changes []domain.RoundEvent
defer func() {
if err := s.repoManager.Events().Save(ctx, round.Id, changes...); err != nil {
log.WithError(err).Warn("failed to store new round events")
return
}
}()
forfeitTxs, leftUnsigned := s.forfeitTxs.pop() forfeitTxs, leftUnsigned := s.forfeitTxs.pop()
if len(leftUnsigned) > 0 { if len(leftUnsigned) > 0 {
err := fmt.Errorf("%d forfeit txs left to sign", len(leftUnsigned)) err := fmt.Errorf("%d forfeit txs left to sign", len(leftUnsigned))
round.Fail(fmt.Errorf("failed to finalize round: %s", err)) changes = round.Fail(fmt.Errorf("failed to finalize round: %s", err))
log.WithError(err).Warn("failed to finalize round") log.WithError(err).Warn("failed to finalize round")
return return
} }
txid, err := s.wallet.BroadcastTransaction(ctx, round.TxHex) txid, err := s.wallet.BroadcastTransaction(ctx, round.TxHex)
if err != nil { if err != nil {
round.Fail(fmt.Errorf("failed to broadcast pool tx: %s", err)) changes = round.Fail(fmt.Errorf("failed to broadcast pool tx: %s", err))
log.WithError(err).Warn("failed to broadcast pool tx") log.WithError(err).Warn("failed to broadcast pool tx")
return return
} }
changes, _ := round.EndFinalization(forfeitTxs, txid) changes, _ = round.EndFinalization(forfeitTxs, txid)
if err := s.repoManager.Events().Save(ctx, round.Id, changes...); err != nil {
log.WithError(err).Warn("failed to store new round events")
return
}
log.Debugf("finalized round %s with pool tx %s", round.Id, round.Txid) log.Debugf("finalized round %s with pool tx %s", round.Id, round.Txid)
} }
@@ -331,6 +349,7 @@ func (s *service) updateProjectionStore(round *domain.Round) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
continue continue
} }
log.Debugf("spent %d vtxos", len(spentVtxos))
break break
} }
} }
@@ -342,6 +361,7 @@ func (s *service) updateProjectionStore(round *domain.Round) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
continue continue
} }
log.Debugf("added %d new vtxos", len(newVtxos))
break break
} }
} }
@@ -359,7 +379,16 @@ func (s *service) updateProjectionStore(round *domain.Round) {
func (s *service) propagateEvents(round *domain.Round) { func (s *service) propagateEvents(round *domain.Round) {
lastEvent := round.Events()[len(round.Events())-1] lastEvent := round.Events()[len(round.Events())-1]
switch e := lastEvent.(type) { switch e := lastEvent.(type) {
case domain.RoundFinalizationStarted, domain.RoundFinalized: case domain.RoundFinalizationStarted:
forfeitTxs := s.forfeitTxs.view()
s.eventsCh <- domain.RoundFinalizationStarted{
Id: e.Id,
CongestionTree: e.CongestionTree,
Connectors: e.Connectors,
PoolTx: e.PoolTx,
UnsignedForfeitTxs: forfeitTxs,
}
case domain.RoundFinalized:
s.eventsCh <- e s.eventsCh <- e
} }
} }
@@ -375,13 +404,13 @@ func getNewVtxos(net network.Network, round *domain.Round) []domain.Vtxo {
found := false found := false
for _, r := range p.Receivers { for _, r := range p.Receivers {
buf, _ := hex.DecodeString(r.Pubkey) buf, _ := hex.DecodeString(r.Pubkey)
pk, _ := btcec.ParsePubKey(buf) pk, _ := secp256k1.ParsePubKey(buf)
p2wpkh := payment.FromPublicKey(pk, &net, nil) p2wpkh := payment.FromPublicKey(pk, &net, nil)
addr, _ := p2wpkh.WitnessPubKeyHash() addr, _ := p2wpkh.WitnessPubKeyHash()
script, _ := address.ToOutputScript(addr) script, _ := address.ToOutputScript(addr)
if bytes.Equal(script, out.Script) { if bytes.Equal(script, out.Script) {
found = true found = true
pubkey = hex.EncodeToString(pk.SerializeCompressed()) pubkey = r.Pubkey
break break
} }
} }

View File

@@ -91,6 +91,7 @@ func (m *paymentsMap) update(payment domain.Payment) error {
} }
p.Payment = payment p.Payment = payment
return nil return nil
} }
@@ -182,3 +183,14 @@ func (m *forfeitTxsMap) pop() (signed, unsigned []string) {
m.forfeitTxs = make(map[string]*signedTx) m.forfeitTxs = make(map[string]*signedTx)
return signed, unsigned return signed, unsigned
} }
func (m *forfeitTxsMap) view() []string {
m.lock.RLock()
defer m.lock.RUnlock()
txs := make([]string, 0, len(m.forfeitTxs))
for _, tx := range m.forfeitTxs {
txs = append(txs, tx.tx)
}
return txs
}

View File

@@ -4,17 +4,22 @@ type Node struct {
Txid string Txid string
Tx string Tx string
ParentTxid string ParentTxid string
Leaf bool
} }
type CongestionTree [][]Node type CongestionTree [][]Node
func (c CongestionTree) Leaves() []Node { func (c CongestionTree) Leaves() []Node {
length := len(c) leaves := c[len(c)-1]
if length == 0 { for _, level := range c[:len(c)-1] {
return nil for _, node := range level {
if node.Leaf {
leaves = append(leaves, node)
}
}
} }
return c[length-1] return leaves
} }
func (c CongestionTree) NumberOfNodes() int { func (c CongestionTree) NumberOfNodes() int {

View File

@@ -19,6 +19,7 @@ type RoundFinalizationStarted struct {
Id string Id string
CongestionTree CongestionTree CongestionTree CongestionTree
Connectors []string Connectors []string
UnsignedForfeitTxs []string
PoolTx string PoolTx string
} }
@@ -31,7 +32,7 @@ type RoundFinalized struct {
type RoundFailed struct { type RoundFailed struct {
Id string Id string
Err error Err string
Timestamp int64 Timestamp int64
} }

View File

@@ -201,7 +201,7 @@ func (r *Round) Fail(err error) []RoundEvent {
} }
event := RoundFailed{ event := RoundFailed{
Id: r.Id, Id: r.Id,
Err: err, Err: err.Error(),
Timestamp: time.Now().Unix(), Timestamp: time.Now().Unix(),
} }
r.raise(event) r.raise(event)

View File

@@ -508,8 +508,8 @@ func testFail(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, events) require.NotEmpty(t, events)
reason := "some valid reason" reason := fmt.Errorf("some valid reason")
events = round.Fail(fmt.Errorf(reason)) events = round.Fail(reason)
require.Len(t, events, 1) require.Len(t, events, 1)
require.False(t, round.IsStarted()) require.False(t, round.IsStarted())
require.False(t, round.IsEnded()) require.False(t, round.IsEnded())
@@ -519,9 +519,9 @@ func testFail(t *testing.T) {
require.True(t, ok) require.True(t, ok)
require.Exactly(t, round.Id, event.Id) require.Exactly(t, round.Id, event.Id)
require.Exactly(t, round.EndingTimestamp, event.Timestamp) require.Exactly(t, round.EndingTimestamp, event.Timestamp)
require.EqualError(t, event.Err, reason) require.EqualError(t, reason, event.Err)
events = round.Fail(fmt.Errorf(reason)) events = round.Fail(reason)
require.Empty(t, events) require.Empty(t, events)
}) })
}) })

View File

@@ -1,9 +1,18 @@
package ports package ports
import "github.com/ark-network/ark/internal/core/domain" import (
"github.com/ark-network/ark/internal/core/domain"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
)
type TxBuilder interface { type TxBuilder interface {
BuildPoolTx(wallet WalletService, payments []domain.Payment) (poolTx string, err error) BuildPoolTx(
BuildCongestionTree(poolTx string, payments []domain.Payment) (congestionTree domain.CongestionTree, err error) aspPubkey *secp256k1.PublicKey, wallet WalletService, payments []domain.Payment,
BuildForfeitTxs(poolTx string, payments []domain.Payment) (connectors []string, forfeitTxs []string, err error) ) (poolTx string, err error)
BuildCongestionTree(
aspPubkey *secp256k1.PublicKey, poolTx string, payments []domain.Payment,
) (congestionTree domain.CongestionTree, err error)
BuildForfeitTxs(
aspPubkey *secp256k1.PublicKey, poolTx string, payments []domain.Payment,
) (connectors []string, forfeitTxs []string, err error)
} }

View File

@@ -15,6 +15,7 @@ type WalletService interface {
) (string, error) ) (string, error)
Transfer(ctx context.Context, outs []TxOutput) (string, error) Transfer(ctx context.Context, outs []TxOutput) (string, error)
BroadcastTransaction(ctx context.Context, txHex string) (string, error) BroadcastTransaction(ctx context.Context, txHex string) (string, error)
Close()
} }
type WalletStatus interface { type WalletStatus interface {
@@ -33,5 +34,6 @@ type TxInput interface {
type TxOutput interface { type TxOutput interface {
GetAmount() uint64 GetAmount() uint64
GetAsset() string
GetScript() string GetScript() string
} }

View File

@@ -11,6 +11,8 @@ import (
"github.com/timshannon/badgerhold/v4" "github.com/timshannon/badgerhold/v4"
) )
const roundStoreDir = "rounds"
type roundRepository struct { type roundRepository struct {
store *badgerhold.Store store *badgerhold.Store
} }
@@ -33,7 +35,7 @@ func NewRoundRepository(config ...interface{}) (dbtypes.RoundStore, error) {
var dir string var dir string
if len(baseDir) > 0 { if len(baseDir) > 0 {
dir = filepath.Join(baseDir, eventStoreDir) dir = filepath.Join(baseDir, roundStoreDir)
} }
store, err := createDB(dir, logger) store, err := createDB(dir, logger)
if err != nil { if err != nil {
@@ -58,7 +60,7 @@ func (r *roundRepository) GetCurrentRound(
return nil, err return nil, err
} }
if len(rounds) <= 0 { if len(rounds) <= 0 {
return nil, nil return nil, fmt.Errorf("ongoing round not found")
} }
return &rounds[0], nil return &rounds[0], nil
} }

View File

@@ -82,36 +82,32 @@ func serializeEvent(event domain.RoundEvent) ([]byte, error) {
func deserializeEvent(buf []byte) (domain.RoundEvent, error) { func deserializeEvent(buf []byte) (domain.RoundEvent, error) {
{ {
var event = domain.RoundStarted{} var event = domain.RoundFailed{}
if err := json.Unmarshal(buf, &event); err == nil { if err := json.Unmarshal(buf, &event); err == nil && len(event.Err) > 0 {
return event, nil return event, nil
} }
} }
{
var event = domain.RoundFinalizationStarted{}
if err := json.Unmarshal(buf, &event); err == nil {
return event, nil
}
}
{ {
var event = domain.RoundFinalized{} var event = domain.RoundFinalized{}
if err := json.Unmarshal(buf, &event); err == nil { if err := json.Unmarshal(buf, &event); err == nil && len(event.Txid) > 0 {
return event, nil return event, nil
} }
} }
{ {
var event = domain.RoundFailed{} var event = domain.RoundFinalizationStarted{}
if err := json.Unmarshal(buf, &event); err == nil { if err := json.Unmarshal(buf, &event); err == nil && len(event.CongestionTree) > 0 {
return event, nil return event, nil
} }
} }
{ {
var event = domain.PaymentsRegistered{} var event = domain.PaymentsRegistered{}
if err := json.Unmarshal(buf, &event); err == nil { if err := json.Unmarshal(buf, &event); err == nil && len(event.Payments) > 0 {
return event, nil
}
}
{
var event = domain.RoundStarted{}
if err := json.Unmarshal(buf, &event); err == nil && event.Timestamp > 0 {
return event, nil return event, nil
} }
} }

View File

@@ -11,6 +11,8 @@ import (
"github.com/timshannon/badgerhold/v4" "github.com/timshannon/badgerhold/v4"
) )
const vtxoStoreDir = "vtxos"
type vtxoRepository struct { type vtxoRepository struct {
store *badgerhold.Store store *badgerhold.Store
} }
@@ -33,7 +35,7 @@ func NewVtxoRepository(config ...interface{}) (dbtypes.VtxoStore, error) {
var dir string var dir string
if len(baseDir) > 0 { if len(baseDir) > 0 {
dir = filepath.Join(baseDir, eventStoreDir) dir = filepath.Join(baseDir, vtxoStoreDir)
} }
store, err := createDB(dir, logger) store, err := createDB(dir, logger)
if err != nil { if err != nil {

View File

@@ -138,7 +138,8 @@ func testRoundEventRepository(t *testing.T, svc ports.RepoManager) {
handler: func(round *domain.Round) { handler: func(round *domain.Round) {
require.NotNil(t, round) require.NotNil(t, round)
require.Len(t, round.Events(), 2) require.Len(t, round.Events(), 2)
require.Len(t, round.CongestionTree, 7) require.Len(t, round.CongestionTree, 3)
require.Equal(t, round.CongestionTree.NumberOfNodes(), 7)
require.Len(t, round.Connectors, 2) require.Len(t, round.Connectors, 2)
}, },
}, },
@@ -274,7 +275,7 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) {
require.NoError(t, err) require.NoError(t, err)
currentRound, err = svc.Rounds().GetCurrentRound(ctx) currentRound, err = svc.Rounds().GetCurrentRound(ctx)
require.NoError(t, err) require.Error(t, err)
require.Nil(t, currentRound) require.Nil(t, currentRound)
roundById, err = svc.Rounds().GetRoundWithId(ctx, roundId) roundById, err = svc.Rounds().GetRoundWithId(ctx, roundId)

View File

@@ -68,6 +68,7 @@ func (l outputList) toProto() []*pb.Output {
list = append(list, &pb.Output{ list = append(list, &pb.Output{
Amount: out.GetAmount(), Amount: out.GetAmount(),
Script: out.GetScript(), Script: out.GetScript(),
Asset: out.GetAsset(),
}) })
} }
return list return list

View File

@@ -26,9 +26,9 @@ func (s *service) Stop() {
func (s *service) ScheduleTask(interval int64, immediate bool, task func()) error { func (s *service) ScheduleTask(interval int64, immediate bool, task func()) error {
if immediate { if immediate {
_, err := s.scheduler.Every(interval).Seconds().Do(task) _, err := s.scheduler.Every(int(interval)).Seconds().Do(task)
return err return err
} }
_, err := s.scheduler.Every(interval).Seconds().WaitForSchedule().Do(task) _, err := s.scheduler.Every(int(interval)).Seconds().WaitForSchedule().Do(task)
return err return err
} }

View File

@@ -4,12 +4,12 @@ import (
"context" "context"
"encoding/hex" "encoding/hex"
"github.com/ark-network/ark/common"
"github.com/ark-network/ark/internal/core/domain" "github.com/ark-network/ark/internal/core/domain"
"github.com/ark-network/ark/internal/core/ports" "github.com/ark-network/ark/internal/core/ports"
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/network"
"github.com/vulpemventures/go-elements/psetv2" "github.com/vulpemventures/go-elements/psetv2"
"github.com/vulpemventures/go-elements/transaction"
) )
const ( const (
@@ -17,31 +17,18 @@ const (
) )
type txBuilder struct { type txBuilder struct {
net *network.Network net network.Network
aspPublicKey *secp256k1.PublicKey
} }
func toElementsNetwork(net common.Network) *network.Network { func NewTxBuilder(net network.Network) ports.TxBuilder {
switch net { return &txBuilder{net}
case common.MainNet:
return &network.Liquid
case common.TestNet:
return &network.Testnet
default:
return nil
}
}
func NewTxBuilder(aspPublicKey *secp256k1.PublicKey, net common.Network) ports.TxBuilder {
return &txBuilder{
aspPublicKey: aspPublicKey,
net: toElementsNetwork(net),
}
} }
// BuildCongestionTree implements ports.TxBuilder. // BuildCongestionTree implements ports.TxBuilder.
func (b *txBuilder) BuildCongestionTree(poolTx string, payments []domain.Payment) (congestionTree domain.CongestionTree, err error) { func (b *txBuilder) BuildCongestionTree(
poolTxID, err := getTxID(poolTx) aspPubkey *secp256k1.PublicKey, poolTx string, payments []domain.Payment,
) (congestionTree domain.CongestionTree, err error) {
poolTxID, err := getTxid(poolTx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -49,7 +36,7 @@ func (b *txBuilder) BuildCongestionTree(poolTx string, payments []domain.Payment
receivers := receiversFromPayments(payments) receivers := receiversFromPayments(payments)
return buildCongestionTree( return buildCongestionTree(
newOutputScriptFactory(b.aspPublicKey, b.net), newOutputScriptFactory(aspPubkey, b.net),
b.net, b.net,
poolTxID, poolTxID,
receivers, receivers,
@@ -57,13 +44,15 @@ func (b *txBuilder) BuildCongestionTree(poolTx string, payments []domain.Payment
} }
// BuildForfeitTxs implements ports.TxBuilder. // BuildForfeitTxs implements ports.TxBuilder.
func (b *txBuilder) BuildForfeitTxs(poolTx string, payments []domain.Payment) (connectors []string, forfeitTxs []string, err error) { func (b *txBuilder) BuildForfeitTxs(
poolTxID, err := getTxID(poolTx) aspPubkey *secp256k1.PublicKey, poolTx string, payments []domain.Payment,
) (connectors []string, forfeitTxs []string, err error) {
poolTxID, err := getTxid(poolTx)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
aspScript, err := p2wpkhScript(b.aspPublicKey, b.net) aspScript, err := p2wpkhScript(aspPubkey, b.net)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -117,8 +106,10 @@ func (b *txBuilder) BuildForfeitTxs(poolTx string, payments []domain.Payment) (c
} }
// BuildPoolTx implements ports.TxBuilder. // BuildPoolTx implements ports.TxBuilder.
func (b *txBuilder) BuildPoolTx(wallet ports.WalletService, payments []domain.Payment) (poolTx string, err error) { func (b *txBuilder) BuildPoolTx(
aspScriptBytes, err := p2wpkhScript(b.aspPublicKey, b.net) aspPubkey *secp256k1.PublicKey, wallet ports.WalletService, payments []domain.Payment,
) (poolTx string, err error) {
aspScriptBytes, err := p2wpkhScript(aspPubkey, b.net)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -134,41 +125,45 @@ func (b *txBuilder) BuildPoolTx(wallet ports.WalletService, payments []domain.Pa
ctx := context.Background() ctx := context.Background()
return wallet.Transfer(ctx, []ports.TxOutput{ return wallet.Transfer(ctx, []ports.TxOutput{
newOutput(aspScript, sharedOutputAmount), newOutput(aspScript, sharedOutputAmount, b.net.AssetID),
newOutput(aspScript, connectorOutputAmount), newOutput(aspScript, connectorOutputAmount, b.net.AssetID),
}) })
} }
func connectorsToInputArgs(connectors []string) ([]psetv2.InputArgs, error) { func connectorsToInputArgs(connectors []string) ([]psetv2.InputArgs, error) {
inputs := make([]psetv2.InputArgs, 0, len(connectors)+1) inputs := make([]psetv2.InputArgs, 0, len(connectors)+1)
for i, psetb64 := range connectors { for i, psetb64 := range connectors {
txID, err := getTxID(psetb64) tx, err := psetv2.NewPsetFromBase64(psetb64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
utx, err := tx.UnsignedTx()
input := psetv2.InputArgs{ if err != nil {
Txid: txID, return nil, err
TxIndex: 0,
} }
inputs = append(inputs, input) txid := utx.TxHash().String()
for j := range tx.Outputs {
if i == len(connectors)-1 { inputs = append(inputs, psetv2.InputArgs{
input := psetv2.InputArgs{ Txid: txid,
Txid: txID, TxIndex: uint32(j),
TxIndex: 1, })
if i != len(connectors)-1 {
break
} }
inputs = append(inputs, input)
} }
} }
return inputs, nil return inputs, nil
} }
func getTxID(psetBase64 string) (string, error) { func getTxid(txStr string) (string, error) {
pset, err := psetv2.NewPsetFromBase64(psetBase64) pset, err := psetv2.NewPsetFromBase64(txStr)
if err != nil {
tx, err := transaction.NewTxFromHex(txStr)
if err != nil { if err != nil {
return "", err return "", err
} }
return tx.TxHash().String(), nil
}
utx, err := pset.UnsignedTx() utx, err := pset.UnsignedTx()
if err != nil { if err != nil {
@@ -205,12 +200,14 @@ func sumReceivers(receivers []domain.Receiver) uint64 {
type output struct { type output struct {
script string script string
amount uint64 amount uint64
asset string
} }
func newOutput(script string, amount uint64) ports.TxOutput { func newOutput(script string, amount uint64, asset string) ports.TxOutput {
return &output{ return &output{
script: script, script: script,
amount: amount, amount: amount,
asset: asset,
} }
} }
@@ -218,6 +215,10 @@ func (o *output) GetAmount() uint64 {
return o.amount return o.amount
} }
func (o *output) GetAsset() string {
return o.asset
}
func (o *output) GetScript() string { func (o *output) GetScript() string {
return o.script return o.script
} }

View File

@@ -9,7 +9,6 @@ import (
txbuilder "github.com/ark-network/ark/internal/infrastructure/tx-builder/dummy" txbuilder "github.com/ark-network/ark/internal/infrastructure/tx-builder/dummy"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/vulpemventures/go-elements/address"
"github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/network"
"github.com/vulpemventures/go-elements/payment" "github.com/vulpemventures/go-elements/payment"
"github.com/vulpemventures/go-elements/psetv2" "github.com/vulpemventures/go-elements/psetv2"
@@ -20,12 +19,7 @@ const (
) )
func createTestTxBuilder() (ports.TxBuilder, error) { func createTestTxBuilder() (ports.TxBuilder, error) {
_, key, err := common.DecodePubKey(testingKey) return txbuilder.NewTxBuilder(network.Liquid), nil
if err != nil {
return nil, err
}
return txbuilder.NewTxBuilder(key, common.MainNet), nil
} }
func createTestPoolTx(sharedOutputAmount, numberOfInputs uint64) (string, error) { func createTestPoolTx(sharedOutputAmount, numberOfInputs uint64) (string, error) {
@@ -34,16 +28,8 @@ func createTestPoolTx(sharedOutputAmount, numberOfInputs uint64) (string, error)
return "", err return "", err
} }
payment := payment.FromPublicKey(key, &network.Regtest, nil) payment := payment.FromPublicKey(key, &network.Testnet, nil)
addr, err := payment.WitnessPubKeyHash() script := payment.WitnessScript
if err != nil {
return "", err
}
script, err := address.ToOutputScript(addr)
if err != nil {
return "", err
}
pset, err := psetv2.New(nil, nil, nil) pset, err := psetv2.New(nil, nil, nil)
if err != nil { if err != nil {
@@ -108,6 +94,7 @@ func TestBuildCongestionTree(t *testing.T) {
fixtures := []struct { fixtures := []struct {
payments []domain.Payment payments []domain.Payment
expectedNodesNum int // 2*len(receivers)-1 expectedNodesNum int // 2*len(receivers)-1
expectedLeavesNum int
}{ }{
{ {
payments: []domain.Payment{ payments: []domain.Payment{
@@ -120,24 +107,25 @@ func TestBuildCongestionTree(t *testing.T) {
VOut: 0, VOut: 0,
}, },
Receiver: domain.Receiver{ Receiver: domain.Receiver{
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
}, },
}, },
Receivers: []domain.Receiver{ Receivers: []domain.Receiver{
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 400, Amount: 400,
}, },
}, },
}, },
}, },
expectedNodesNum: 3, expectedNodesNum: 3,
expectedLeavesNum: 2,
}, },
{ {
payments: []domain.Payment{ payments: []domain.Payment{
@@ -150,18 +138,18 @@ func TestBuildCongestionTree(t *testing.T) {
VOut: 0, VOut: 0,
}, },
Receiver: domain.Receiver{ Receiver: domain.Receiver{
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
}, },
}, },
Receivers: []domain.Receiver{ Receivers: []domain.Receiver{
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 400, Amount: 400,
}, },
}, },
@@ -175,18 +163,18 @@ func TestBuildCongestionTree(t *testing.T) {
VOut: 0, VOut: 0,
}, },
Receiver: domain.Receiver{ Receiver: domain.Receiver{
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
}, },
}, },
Receivers: []domain.Receiver{ Receivers: []domain.Receiver{
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 400, Amount: 400,
}, },
}, },
@@ -200,31 +188,37 @@ func TestBuildCongestionTree(t *testing.T) {
VOut: 0, VOut: 0,
}, },
Receiver: domain.Receiver{ Receiver: domain.Receiver{
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
}, },
}, },
Receivers: []domain.Receiver{ Receivers: []domain.Receiver{
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 400, Amount: 400,
}, },
}, },
}, },
}, },
expectedNodesNum: 11, expectedNodesNum: 11,
expectedLeavesNum: 6,
}, },
} }
_, key, err := common.DecodePubKey(testingKey)
require.NoError(t, err)
require.NotNil(t, key)
for _, f := range fixtures { for _, f := range fixtures {
tree, err := builder.BuildCongestionTree(poolTx, f.payments) tree, err := builder.BuildCongestionTree(key, poolTx, f.payments)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, f.expectedNodesNum, tree.NumberOfNodes()) require.Equal(t, f.expectedNodesNum, tree.NumberOfNodes())
require.Len(t, tree.Leaves(), f.expectedLeavesNum)
// check the root // check the root
require.Len(t, tree[0], 1) require.Len(t, tree[0], 1)
@@ -298,7 +292,7 @@ func TestBuildForfeitTxs(t *testing.T) {
VOut: 0, VOut: 0,
}, },
Receiver: domain.Receiver{ Receiver: domain.Receiver{
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
}, },
@@ -308,18 +302,18 @@ func TestBuildForfeitTxs(t *testing.T) {
VOut: 1, VOut: 1,
}, },
Receiver: domain.Receiver{ Receiver: domain.Receiver{
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 400, Amount: 400,
}, },
}, },
}, },
Receivers: []domain.Receiver{ Receivers: []domain.Receiver{
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 600, Amount: 600,
}, },
{ {
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x", Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
Amount: 400, Amount: 400,
}, },
}, },
@@ -330,10 +324,15 @@ func TestBuildForfeitTxs(t *testing.T) {
}, },
} }
for _, f := range fixtures { _, key, err := common.DecodePubKey(testingKey)
connectors, forfeitTxs, err := builder.BuildForfeitTxs(poolTx, f.payments)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, key)
for _, f := range fixtures {
connectors, forfeitTxs, err := builder.BuildForfeitTxs(
key, poolTx, f.payments,
)
require.NoError(t, err)
require.Len(t, connectors, f.expectedNumOfConnectors) require.Len(t, connectors, f.expectedNumOfConnectors)
require.Len(t, forfeitTxs, f.expectedNumOfForfeitTxs) require.Len(t, forfeitTxs, f.expectedNumOfForfeitTxs)

View File

@@ -16,6 +16,34 @@ func createConnectors(
TxIndex: connectorOutputIndex, TxIndex: connectorOutputIndex,
} }
if numberOfConnectors == 1 {
pset, err := psetv2.New(nil, nil, nil)
if err != nil {
return nil, err
}
updater, err := psetv2.NewUpdater(pset)
if err != nil {
return nil, err
}
err = updater.AddInputs([]psetv2.InputArgs{previousInput})
if err != nil {
return nil, err
}
err = updater.AddOutputs([]psetv2.OutputArgs{connectorOutput})
if err != nil {
return nil, err
}
base64, err := pset.ToBase64()
if err != nil {
return nil, err
}
return []string{base64}, nil
}
// compute the initial amount of the connectors output in pool transaction // compute the initial amount of the connectors output in pool transaction
remainingAmount := connectorAmount * numberOfConnectors remainingAmount := connectorAmount * numberOfConnectors

View File

@@ -10,7 +10,7 @@ func createForfeitTx(
vtxoInput psetv2.InputArgs, vtxoInput psetv2.InputArgs,
vtxoAmount uint64, vtxoAmount uint64,
aspScript []byte, aspScript []byte,
net *network.Network, net network.Network,
) (forfeitTx string, err error) { ) (forfeitTx string, err error) {
pset, err := psetv2.New(nil, nil, nil) pset, err := psetv2.New(nil, nil, nil)
if err != nil { if err != nil {

View File

@@ -1,7 +1,8 @@
package txbuilder package txbuilder
import ( import (
"github.com/ark-network/ark/common" "encoding/hex"
"github.com/ark-network/ark/internal/core/domain" "github.com/ark-network/ark/internal/core/domain"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
@@ -17,8 +18,8 @@ const (
type outputScriptFactory func(leaves []domain.Receiver) ([]byte, error) type outputScriptFactory func(leaves []domain.Receiver) ([]byte, error)
func p2wpkhScript(publicKey *secp256k1.PublicKey, net *network.Network) ([]byte, error) { func p2wpkhScript(publicKey *secp256k1.PublicKey, net network.Network) ([]byte, error) {
payment := payment.FromPublicKey(publicKey, net, nil) payment := payment.FromPublicKey(publicKey, &net, nil)
addr, err := payment.WitnessPubKeyHash() addr, err := payment.WitnessPubKeyHash()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -28,7 +29,7 @@ func p2wpkhScript(publicKey *secp256k1.PublicKey, net *network.Network) ([]byte,
} }
// newOtputScriptFactory returns an output script factory func that lock funds using the ASP public key only on all branches psbt. The leaves are instead locked by the leaf public key. // newOtputScriptFactory returns an output script factory func that lock funds using the ASP public key only on all branches psbt. The leaves are instead locked by the leaf public key.
func newOutputScriptFactory(aspPublicKey *secp256k1.PublicKey, net *network.Network) outputScriptFactory { func newOutputScriptFactory(aspPublicKey *secp256k1.PublicKey, net network.Network) outputScriptFactory {
return func(leaves []domain.Receiver) ([]byte, error) { return func(leaves []domain.Receiver) ([]byte, error) {
aspScript, err := p2wpkhScript(aspPublicKey, net) aspScript, err := p2wpkhScript(aspPublicKey, net)
if err != nil { if err != nil {
@@ -39,7 +40,11 @@ func newOutputScriptFactory(aspPublicKey *secp256k1.PublicKey, net *network.Netw
case 0: case 0:
return nil, nil return nil, nil
case 1: // it's a leaf case 1: // it's a leaf
_, key, err := common.DecodePubKey(leaves[0].Pubkey) buf, err := hex.DecodeString(leaves[0].Pubkey)
if err != nil {
return nil, err
}
key, err := secp256k1.ParsePubKey(buf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -55,7 +60,7 @@ func newOutputScriptFactory(aspPublicKey *secp256k1.PublicKey, net *network.Netw
// it also expect createOutputScript func managing the output script creation and the network to use (mainly for L-BTC asset id) // it also expect createOutputScript func managing the output script creation and the network to use (mainly for L-BTC asset id)
func buildCongestionTree( func buildCongestionTree(
createOutputScript outputScriptFactory, createOutputScript outputScriptFactory,
net *network.Network, net network.Network,
poolTxID string, poolTxID string,
receivers []domain.Receiver, receivers []domain.Receiver,
) (congestionTree domain.CongestionTree, err error) { ) (congestionTree domain.CongestionTree, err error) {
@@ -108,6 +113,7 @@ func buildCongestionTree(
Txid: txid, Txid: txid,
Tx: psetB64, Tx: psetB64,
ParentTxid: parentTxid, ParentTxid: parentTxid,
Leaf: psetWithLevel.leaf,
}) })
} }
@@ -138,13 +144,13 @@ type node struct {
left *node left *node
right *node right *node
createOutputScript outputScriptFactory createOutputScript outputScriptFactory
network *network.Network network network.Network
} }
// create a node from a single receiver // create a node from a single receiver
func newLeaf( func newLeaf(
createOutputScript outputScriptFactory, createOutputScript outputScriptFactory,
network *network.Network, network network.Network,
receiver domain.Receiver, receiver domain.Receiver,
) *node { ) *node {
return &node{ return &node{
@@ -172,7 +178,7 @@ func newBranch(
// is it the final node of the tree // is it the final node of the tree
func (n *node) isLeaf() bool { func (n *node) isLeaf() bool {
return len(n.receivers) == 1 return n.left == nil && n.right == nil
} }
// compute the output amount of a node // compute the output amount of a node
@@ -256,6 +262,7 @@ func (n *node) pset(input psetv2.InputArgs) (*psetv2.Pset, error) {
type psetWithLevel struct { type psetWithLevel struct {
pset *psetv2.Pset pset *psetv2.Pset
level int level int
leaf bool
} }
// create the node pset and all the psets of its children recursively, updating the input arg at each step // create the node pset and all the psets of its children recursively, updating the input arg at each step
@@ -267,7 +274,7 @@ func (n *node) psets(input psetv2.InputArgs, level int) ([]psetWithLevel, error)
} }
nodeResult := []psetWithLevel{ nodeResult := []psetWithLevel{
{pset, level}, {pset, level, n.isLeaf()},
} }
if n.isLeaf() { if n.isLeaf() {

View File

@@ -0,0 +1,46 @@
package grpcservice
import (
"crypto/tls"
"fmt"
"net"
)
type Config struct {
Port uint32
NoTLS bool
}
func (c Config) Validate() error {
lis, err := net.Listen("tcp", c.address())
if err != nil {
return fmt.Errorf("invalid port: %s", err)
}
defer lis.Close()
if !c.NoTLS {
return fmt.Errorf("tls termination not supported yet")
}
return nil
}
func (c Config) insecure() bool {
return c.NoTLS
}
func (c Config) address() string {
return fmt.Sprintf(":%d", c.Port)
}
func (c Config) listener() net.Listener {
lis, _ := net.Listen("tcp", c.address())
if c.insecure() {
return lis
}
return tls.NewListener(lis, c.tlsConfig())
}
func (c Config) tlsConfig() *tls.Config {
return nil
}

View File

@@ -7,7 +7,6 @@ import (
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1" arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/ark-network/ark/internal/core/application" "github.com/ark-network/ark/internal/core/application"
"github.com/ark-network/ark/internal/core/domain" "github.com/ark-network/ark/internal/core/domain"
"github.com/ark-network/ark/internal/core/ports"
"github.com/google/uuid" "github.com/google/uuid"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@@ -25,7 +24,7 @@ type handler struct {
listeners []*listener listeners []*listener
} }
func NewHandler(service application.Service, repoManager ports.RepoManager) arkv1.ArkServiceServer { func NewHandler(service application.Service) arkv1.ArkServiceServer {
h := &handler{ h := &handler{
svc: service, svc: service,
listenersLock: &sync.Mutex{}, listenersLock: &sync.Mutex{},
@@ -154,6 +153,9 @@ func (h *handler) GetEventStream(_ *arkv1.GetEventStreamRequest, stream arkv1.Ar
switch ev.Event.(type) { switch ev.Event.(type) {
case *arkv1.GetEventStreamResponse_RoundFinalized, *arkv1.GetEventStreamResponse_RoundFailed: case *arkv1.GetEventStreamResponse_RoundFinalized, *arkv1.GetEventStreamResponse_RoundFailed:
if err := stream.Send(ev); err != nil {
return err
}
return nil return nil
} }
} }
@@ -220,7 +222,7 @@ func (h *handler) listenToEvents() {
Id: e.Id, Id: e.Id,
PoolPartialTx: e.PoolTx, PoolPartialTx: e.PoolTx,
CongestionTree: castCongestionTree(e.CongestionTree), CongestionTree: castCongestionTree(e.CongestionTree),
ForfeitTxs: nil, // TODO: add forfeit txs ForfeitTxs: e.UnsignedForfeitTxs,
}, },
}, },
} }
@@ -238,7 +240,7 @@ func (h *handler) listenToEvents() {
Event: &arkv1.GetEventStreamResponse_RoundFailed{ Event: &arkv1.GetEventStreamResponse_RoundFailed{
RoundFailed: &arkv1.RoundFailed{ RoundFailed: &arkv1.RoundFailed{
Id: e.Id, Id: e.Id,
Reason: e.Err.Error(), Reason: e.Err,
}, },
}, },
} }

View File

@@ -1,10 +1,10 @@
package handlers package handlers
import ( import (
"encoding/hex"
"fmt" "fmt"
"github.com/ark-network/ark/common" "github.com/ark-network/ark/common"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/vulpemventures/go-elements/psetv2" "github.com/vulpemventures/go-elements/psetv2"
) )
@@ -20,14 +20,13 @@ func parseTxs(txs []string) ([]string, error) {
return txs, nil return txs, nil
} }
func parseAddress(addr string) (string, error) { func parseAddress(addr string) (*secp256k1.PublicKey, error) {
if len(addr) <= 0 { if len(addr) <= 0 {
return "", fmt.Errorf("missing address") return nil, fmt.Errorf("missing address")
} }
_, userPubkey, _, err := common.DecodeAddress(addr) _, userPubkey, _, err := common.DecodeAddress(addr)
if err != nil { if err != nil {
return "", fmt.Errorf("invalid address: %s", err) return nil, fmt.Errorf("invalid address: %s", err)
} }
pubkey := hex.EncodeToString(userPubkey.SerializeCompressed()) return userPubkey, nil
return pubkey, nil
} }

View File

@@ -0,0 +1,16 @@
package interceptors
import (
middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"google.golang.org/grpc"
)
// UnaryInterceptor returns the unary interceptor
func UnaryInterceptor() grpc.ServerOption {
return grpc.UnaryInterceptor(middleware.ChainUnaryServer(unaryLogger))
}
// StreamInterceptor returns the stream interceptor with a logrus log
func StreamInterceptor() grpc.ServerOption {
return grpc.StreamInterceptor(middleware.ChainStreamServer(streamLogger))
}

View File

@@ -0,0 +1,28 @@
package interceptors
import (
"context"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
)
func unaryLogger(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (interface{}, error) {
log.Debugf("gRPC method: %s", info.FullMethod)
return handler(ctx, req)
}
func streamLogger(
srv interface{},
stream grpc.ServerStream,
info *grpc.StreamServerInfo,
handler grpc.StreamHandler,
) error {
log.Debugf("gRPC method: %s", info.FullMethod)
return handler(srv, stream)
}

View File

@@ -0,0 +1,63 @@
package grpcservice
import (
"fmt"
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
appconfig "github.com/ark-network/ark/internal/app-config"
interfaces "github.com/ark-network/ark/internal/interface"
"github.com/ark-network/ark/internal/interface/grpc/handlers"
"github.com/ark-network/ark/internal/interface/grpc/interceptors"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
type service struct {
config Config
appConfig *appconfig.Config
server *grpc.Server
}
func NewService(
svcConfig Config, appConfig *appconfig.Config,
) (interfaces.Service, error) {
if err := svcConfig.Validate(); err != nil {
return nil, fmt.Errorf("invalid service config: %s", err)
}
if err := appConfig.Validate(); err != nil {
return nil, fmt.Errorf("invalid app config: %s", err)
}
grpcConfig := []grpc.ServerOption{
interceptors.UnaryInterceptor(), interceptors.StreamInterceptor(),
}
if !svcConfig.NoTLS {
return nil, fmt.Errorf("tls termination not supported yet")
}
creds := insecure.NewCredentials()
grpcConfig = append(grpcConfig, grpc.Creds(creds))
server := grpc.NewServer(grpcConfig...)
handler := handlers.NewHandler(appConfig.AppService())
arkv1.RegisterArkServiceServer(server, handler)
return &service{svcConfig, appConfig, server}, nil
}
func (s *service) Start() error {
// nolint:all
go s.server.Serve(s.config.listener())
log.Infof("started listening at %s", s.config.address())
if err := s.appConfig.AppService().Start(); err != nil {
return fmt.Errorf("failed to start app service: %s", err)
}
log.Info("started app service")
return nil
}
func (s *service) Stop() {
s.server.Stop()
log.Info("stopped grpc server")
s.appConfig.AppService().Stop()
log.Info("stopped app service")
}

View File

@@ -1,49 +1,6 @@
package interfaces package interfaces
import (
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
"github.com/ark-network/ark/internal/core/application"
"github.com/ark-network/ark/internal/core/ports"
"github.com/ark-network/ark/internal/interface/grpc/handlers"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
// TODO: Edit this file to something more meaningful for your application.
type Service interface { type Service interface {
Start() error Start() error
Stop() Stop()
} }
type service struct {
grpcService arkv1.ArkServiceServer
grpcServer *grpc.Server
}
type Options struct {
applicationService application.Service
repositoryManager ports.RepoManager
}
func NewService(opts Options) (Service, error) {
return &service{
grpcService: handlers.NewHandler(opts.applicationService, opts.repositoryManager),
}, nil
}
// Start implements Service.
func (s *service) Start() error {
creds := insecure.NewCredentials()
serverOpts := grpc.Creds(creds)
server := grpc.NewServer(serverOpts)
arkv1.RegisterArkServiceServer(server, s.grpcService)
s.grpcServer = server
return nil
}
// Stop implements Service.
func (s *service) Stop() {
s.grpcServer.Stop()
}

View File

@@ -66,9 +66,9 @@ func getConn(ctx *cli.Context) (*grpc.ClientConn, error) {
return nil, err return nil, err
} }
rpcUrl, ok := state["rpc_url"] rpcUrl, ok := state["ark_url"]
if !ok { if !ok {
return nil, fmt.Errorf("missing rpc_url") return nil, fmt.Errorf("missing ark_url")
} }
conn, err := grpc.Dial(rpcUrl, grpc.WithTransportCredentials(insecure.NewCredentials())) conn, err := grpc.Dial(rpcUrl, grpc.WithTransportCredentials(insecure.NewCredentials()))

View File

@@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"io" "io"
@@ -47,6 +48,14 @@ func faucetAction(ctx *cli.Context) error {
return err return err
} }
if event.GetRoundFinalization() != nil {
if _, err := client.FinalizePayment(context.Background(), &arkv1.FinalizePaymentRequest{
SignedForfeitTxs: event.GetRoundFinalization().GetForfeitTxs(),
}); err != nil {
return err
}
}
if event.GetRoundFailed() != nil { if event.GetRoundFailed() != nil {
return fmt.Errorf("faucet failed: %s", event.GetRoundFailed().GetReason()) return fmt.Errorf("faucet failed: %s", event.GetRoundFailed().GetReason())
} }

View File

@@ -28,7 +28,6 @@ require (
require ( require (
github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/gogo/protobuf v1.3.2
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect

View File

@@ -44,8 +44,6 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 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/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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/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.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -69,8 +67,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
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-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 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.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -101,30 +97,19 @@ github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCz
github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM= github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/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-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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/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-20180906233101-161cd47e91fd/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-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-20200226121028-0de0cce0169b/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-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-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -134,7 +119,6 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-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-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
@@ -145,11 +129,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4 h1:W12Pwm4urIbRdGhMEg2NM9O3TWKjNcxQhs46V0ypf/k= google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4 h1:W12Pwm4urIbRdGhMEg2NM9O3TWKjNcxQhs46V0ypf/k=

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@@ -16,7 +17,7 @@ import (
type receiver struct { type receiver struct {
To string `json:"to"` To string `json:"to"`
Amount int64 `json:"amount"` Amount uint64 `json:"amount"`
} }
var ( var (
@@ -55,7 +56,6 @@ func sendAction(ctx *cli.Context) error {
receiversOutput := make([]*arkv1.Output, 0) receiversOutput := make([]*arkv1.Output, 0)
sumOfReceivers := uint64(0) sumOfReceivers := uint64(0)
net := getNetwork()
for _, receiver := range receiversJSON { for _, receiver := range receiversJSON {
_, userKey, aspKey, err := common.DecodeAddress(receiver.To) _, userKey, aspKey, err := common.DecodeAddress(receiver.To)
@@ -71,15 +71,12 @@ func sendAction(ctx *cli.Context) error {
return fmt.Errorf("invalid amount: %d", receiver.Amount) return fmt.Errorf("invalid amount: %d", receiver.Amount)
} }
encodedKey, err := common.EncodePubKey(net.PubKey, userKey) encodedKey := hex.EncodeToString(userKey.SerializeCompressed())
if err != nil {
return err
}
receiversOutput = append(receiversOutput, &arkv1.Output{ receiversOutput = append(receiversOutput, &arkv1.Output{
Pubkey: encodedKey, Pubkey: encodedKey,
Amount: uint64(receiver.Amount), Amount: uint64(receiver.Amount),
}) })
sumOfReceivers += receiver.Amount
} }
client, close, err := getArkClient(ctx) client, close, err := getArkClient(ctx)
if err != nil { if err != nil {
@@ -104,10 +101,7 @@ func sendAction(ctx *cli.Context) error {
} }
walletPubKey := walletPrvKey.PubKey() walletPubKey := walletPrvKey.PubKey()
encodedPubKey, err := common.EncodePubKey(net.PubKey, walletPubKey) encodedPubKey := hex.EncodeToString(walletPubKey.SerializeCompressed())
if err != nil {
return err
}
changeReceiver := &arkv1.Output{ changeReceiver := &arkv1.Output{
Pubkey: encodedPubKey, Pubkey: encodedPubKey,