mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-18 20:54:20 +01:00
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:
committed by
GitHub
parent
e5df6cfc39
commit
3985bd4e14
@@ -34,6 +34,7 @@ lint:
|
||||
run: clean
|
||||
@echo "Running arkd in dev mode..."
|
||||
@export ARK_WALLET_ADDR=localhost:18000; \
|
||||
export ARK_ROUND_INTERVAL=30; \
|
||||
go run ./cmd/arkd
|
||||
|
||||
## test: runs unit and component tests
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
"os/signal"
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -17,7 +19,27 @@ var (
|
||||
)
|
||||
|
||||
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 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
42
asp/go.mod
42
asp/go.mod
@@ -6,11 +6,12 @@ replace github.com/ark-network/ark/common => ../common
|
||||
|
||||
require (
|
||||
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/dgraph-io/badger/v4 v4.1.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/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/viper v1.17.0
|
||||
@@ -23,41 +24,34 @@ require (
|
||||
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 (
|
||||
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/chaincfg/chainhash v1.0.1
|
||||
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/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/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/snappy v0.0.4 // indirect
|
||||
github.com/google/flatbuffers v23.5.9+incompatible // 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/mitchellh/mapstructure v1.5.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/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/slog-shim v0.1.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/subosito/gotenv v1.6.0 // 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/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/net v0.17.0 // indirect
|
||||
golang.org/x/sys v0.13.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
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
21
asp/go.sum
21
asp/go.sum
@@ -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/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/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.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
|
||||
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/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-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/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
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.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/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/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y=
|
||||
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.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
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.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
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/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
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/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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
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/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
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/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
|
||||
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.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
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.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
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/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/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-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
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-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-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-20190507160741-ecd444e8653b/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-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-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-20220715151400-c0bba94af5f8/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-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-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-20191115202509-3a792d9c32b2/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-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-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-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
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.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.8/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-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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
170
asp/internal/app-config/config.go
Normal file
170
asp/internal/app-config/config.go
Normal 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
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
common "github.com/ark-network/ark/common"
|
||||
"github.com/spf13/viper"
|
||||
@@ -11,15 +13,37 @@ import (
|
||||
type Config struct {
|
||||
WalletAddr string
|
||||
RoundInterval int64
|
||||
Port uint32
|
||||
DbType string
|
||||
DbDir string
|
||||
SchedulerType string
|
||||
TxBuilderType string
|
||||
NoTLS bool
|
||||
Network common.Network
|
||||
LogLevel int
|
||||
}
|
||||
|
||||
var (
|
||||
Datadir = "DATADIR"
|
||||
WalletAddr = "WALLET_ADDR"
|
||||
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)
|
||||
defaultRoundInterval = 60
|
||||
defaultPort = 6000
|
||||
defaultDbType = "badger"
|
||||
defaultSchedulerType = "gocron"
|
||||
defaultTxBuilderType = "dummy"
|
||||
defaultInsecure = true
|
||||
defaultNetwork = "testnet"
|
||||
defaultLogLevel = 5
|
||||
)
|
||||
|
||||
func LoadConfig() (*Config, error) {
|
||||
@@ -28,30 +52,35 @@ func LoadConfig() (*Config, error) {
|
||||
|
||||
viper.SetDefault(Datadir, defaultDatadir)
|
||||
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 {
|
||||
return nil, fmt.Errorf("error while creating datadir: %s", err)
|
||||
}
|
||||
|
||||
cfg := &Config{
|
||||
return &Config{
|
||||
WalletAddr: viper.GetString(WalletAddr),
|
||||
RoundInterval: viper.GetInt64(RoundInterval),
|
||||
}
|
||||
|
||||
if err := cfg.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (c *Config) validate() error {
|
||||
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
|
||||
Port: viper.GetUint32(Port),
|
||||
DbType: viper.GetString(DbType),
|
||||
SchedulerType: viper.GetString(SchedulerType),
|
||||
TxBuilderType: viper.GetString(TxBuilderType),
|
||||
NoTLS: viper.GetBool(Insecure),
|
||||
DbDir: filepath.Join(viper.GetString(Datadir), "db"),
|
||||
LogLevel: viper.GetInt(LogLevel),
|
||||
Network: net,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func initDatadir() error {
|
||||
@@ -65,3 +94,14 @@ func makeDirectoryIfNotExists(path string) error {
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/ark-network/ark/internal/core/domain"
|
||||
"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"
|
||||
"github.com/vulpemventures/go-elements/address"
|
||||
"github.com/vulpemventures/go-elements/network"
|
||||
@@ -28,14 +28,16 @@ var (
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
Start() error
|
||||
Stop()
|
||||
SpendVtxos(ctx context.Context, inputs []domain.VtxoKey) (string, error)
|
||||
ClaimVtxos(ctx context.Context, creds string, receivers []domain.Receiver) 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)
|
||||
GetEventsChannel(ctx context.Context) <-chan domain.RoundEvent
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -43,10 +45,9 @@ type service struct {
|
||||
roundInterval int64
|
||||
network common.Network
|
||||
onchainNework network.Network
|
||||
pubkey string
|
||||
pubkey *secp256k1.PublicKey
|
||||
|
||||
wallet ports.WalletService
|
||||
scheduler ports.SchedulerService
|
||||
repoManager ports.RepoManager
|
||||
builder ports.TxBuilder
|
||||
paymentRequests *paymentsMap
|
||||
@@ -57,16 +58,18 @@ type service struct {
|
||||
|
||||
func NewService(
|
||||
interval int64, network common.Network, onchainNetwork network.Network,
|
||||
walletSvc ports.WalletService, schedulerSvc ports.SchedulerService,
|
||||
repoManager ports.RepoManager, builder ports.TxBuilder,
|
||||
) Service {
|
||||
pubkey := ""
|
||||
walletSvc ports.WalletService, repoManager ports.RepoManager, builder ports.TxBuilder,
|
||||
) (Service, error) {
|
||||
eventsCh := make(chan domain.RoundEvent)
|
||||
paymentRequests := newPaymentsMap(nil)
|
||||
forfeitTxs := newForfeitTxsMap()
|
||||
pubkey, err := walletSvc.GetPubkey(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch pubkey: %s", err)
|
||||
}
|
||||
svc := &service{
|
||||
interval, network, onchainNetwork, pubkey,
|
||||
walletSvc, schedulerSvc, repoManager, builder, paymentRequests, forfeitTxs,
|
||||
walletSvc, repoManager, builder, paymentRequests, forfeitTxs,
|
||||
eventsCh,
|
||||
}
|
||||
repoManager.RegisterEventsHandler(
|
||||
@@ -75,13 +78,21 @@ func NewService(
|
||||
svc.propagateEvents(round)
|
||||
},
|
||||
)
|
||||
return svc
|
||||
return svc, nil
|
||||
}
|
||||
|
||||
func (s *service) Start() error {
|
||||
log.Debug("starting app service")
|
||||
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) {
|
||||
vtxos, err := s.repoManager.Vtxos().GetVtxos(ctx, inputs)
|
||||
if err != nil {
|
||||
@@ -120,13 +131,15 @@ func (s *service) UpdatePaymentStatus(_ context.Context, id string) error {
|
||||
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{
|
||||
{
|
||||
VtxoKey: faucetVtxo,
|
||||
Receiver: domain.Receiver{
|
||||
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{
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 10000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
{Pubkey: pubkey, Amount: 1000},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -162,8 +175,9 @@ func (s *service) SignVtxos(ctx context.Context, forfeitTxs []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) ListVtxos(ctx context.Context, pubkey string) ([]domain.Vtxo, error) {
|
||||
return s.repoManager.Vtxos().GetSpendableVtxosWithPubkey(ctx, pubkey)
|
||||
func (s *service) ListVtxos(ctx context.Context, pubkey *secp256k1.PublicKey) ([]domain.Vtxo, error) {
|
||||
pk := hex.EncodeToString(pubkey.SerializeCompressed())
|
||||
return s.repoManager.Vtxos().GetSpendableVtxosWithPubkey(ctx, pk)
|
||||
}
|
||||
|
||||
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) {
|
||||
if s.pubkey == "" {
|
||||
pubkey, err := s.wallet.GetPubkey(ctx)
|
||||
pubkey, err := common.EncodePubKey(s.network.PubKey, s.pubkey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
serializedPubkey, err := common.EncodePubKey(s.network.PubKey, pubkey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s.pubkey = serializedPubkey
|
||||
}
|
||||
return s.pubkey, nil
|
||||
return pubkey, nil
|
||||
}
|
||||
|
||||
func (s *service) start() error {
|
||||
startImmediately := true
|
||||
finalizationInterval := int64(s.roundInterval / 2)
|
||||
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,
|
||||
)
|
||||
s.startRound()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) startRound() {
|
||||
@@ -217,6 +211,11 @@ func (s *service) startRound() {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -227,6 +226,16 @@ func (s *service) startFinalization() {
|
||||
log.WithError(err).Warn("failed to retrieve current round")
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if round.IsFailed() {
|
||||
s.startRound()
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Duration((s.roundInterval/2)-1) * time.Second)
|
||||
s.finalizeRound()
|
||||
}()
|
||||
|
||||
if round.IsFailed() {
|
||||
return
|
||||
}
|
||||
@@ -251,29 +260,33 @@ func (s *service) startFinalization() {
|
||||
num = paymentsThreshold
|
||||
}
|
||||
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 {
|
||||
changes = round.Fail(fmt.Errorf("failed to create pool tx: %s", err))
|
||||
log.WithError(err).Warn("failed to create pool tx")
|
||||
return
|
||||
}
|
||||
|
||||
tree, err := s.builder.BuildCongestionTree(signedPoolTx, payments)
|
||||
tree, err := s.builder.BuildCongestionTree(s.pubkey, signedPoolTx, payments)
|
||||
if err != nil {
|
||||
changes = round.Fail(fmt.Errorf("failed to create congestion tree: %s", err))
|
||||
log.WithError(err).Warn("failed to create congestion tree")
|
||||
return
|
||||
}
|
||||
|
||||
connectors, forfeitTxs, err := s.builder.BuildForfeitTxs(signedPoolTx, payments)
|
||||
connectors, forfeitTxs, err := s.builder.BuildForfeitTxs(s.pubkey, signedPoolTx, payments)
|
||||
if err != nil {
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
||||
events, _ := round.StartFinalization(connectors, tree, signedPoolTx)
|
||||
changes = append(changes, events...)
|
||||
|
||||
@@ -283,6 +296,8 @@ func (s *service) startFinalization() {
|
||||
}
|
||||
|
||||
func (s *service) finalizeRound() {
|
||||
defer s.startRound()
|
||||
|
||||
ctx := context.Background()
|
||||
round, err := s.repoManager.Rounds().GetCurrentRound(ctx)
|
||||
if err != nil {
|
||||
@@ -293,27 +308,30 @@ func (s *service) finalizeRound() {
|
||||
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()
|
||||
if len(leftUnsigned) > 0 {
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
||||
txid, err := s.wallet.BroadcastTransaction(ctx, round.TxHex)
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
changes, _ = round.EndFinalization(forfeitTxs, 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)
|
||||
continue
|
||||
}
|
||||
log.Debugf("spent %d vtxos", len(spentVtxos))
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -342,6 +361,7 @@ func (s *service) updateProjectionStore(round *domain.Round) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
log.Debugf("added %d new vtxos", len(newVtxos))
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -359,7 +379,16 @@ func (s *service) updateProjectionStore(round *domain.Round) {
|
||||
func (s *service) propagateEvents(round *domain.Round) {
|
||||
lastEvent := round.Events()[len(round.Events())-1]
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -375,13 +404,13 @@ func getNewVtxos(net network.Network, round *domain.Round) []domain.Vtxo {
|
||||
found := false
|
||||
for _, r := range p.Receivers {
|
||||
buf, _ := hex.DecodeString(r.Pubkey)
|
||||
pk, _ := btcec.ParsePubKey(buf)
|
||||
pk, _ := secp256k1.ParsePubKey(buf)
|
||||
p2wpkh := payment.FromPublicKey(pk, &net, nil)
|
||||
addr, _ := p2wpkh.WitnessPubKeyHash()
|
||||
script, _ := address.ToOutputScript(addr)
|
||||
if bytes.Equal(script, out.Script) {
|
||||
found = true
|
||||
pubkey = hex.EncodeToString(pk.SerializeCompressed())
|
||||
pubkey = r.Pubkey
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ func (m *paymentsMap) update(payment domain.Payment) error {
|
||||
}
|
||||
|
||||
p.Payment = payment
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -182,3 +183,14 @@ func (m *forfeitTxsMap) pop() (signed, unsigned []string) {
|
||||
m.forfeitTxs = make(map[string]*signedTx)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -4,17 +4,22 @@ type Node struct {
|
||||
Txid string
|
||||
Tx string
|
||||
ParentTxid string
|
||||
Leaf bool
|
||||
}
|
||||
|
||||
type CongestionTree [][]Node
|
||||
|
||||
func (c CongestionTree) Leaves() []Node {
|
||||
length := len(c)
|
||||
if length == 0 {
|
||||
return nil
|
||||
leaves := c[len(c)-1]
|
||||
for _, level := range c[:len(c)-1] {
|
||||
for _, node := range level {
|
||||
if node.Leaf {
|
||||
leaves = append(leaves, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c[length-1]
|
||||
return leaves
|
||||
}
|
||||
|
||||
func (c CongestionTree) NumberOfNodes() int {
|
||||
|
||||
@@ -19,6 +19,7 @@ type RoundFinalizationStarted struct {
|
||||
Id string
|
||||
CongestionTree CongestionTree
|
||||
Connectors []string
|
||||
UnsignedForfeitTxs []string
|
||||
PoolTx string
|
||||
}
|
||||
|
||||
@@ -31,7 +32,7 @@ type RoundFinalized struct {
|
||||
|
||||
type RoundFailed struct {
|
||||
Id string
|
||||
Err error
|
||||
Err string
|
||||
Timestamp int64
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ func (r *Round) Fail(err error) []RoundEvent {
|
||||
}
|
||||
event := RoundFailed{
|
||||
Id: r.Id,
|
||||
Err: err,
|
||||
Err: err.Error(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
r.raise(event)
|
||||
|
||||
@@ -508,8 +508,8 @@ func testFail(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, events)
|
||||
|
||||
reason := "some valid reason"
|
||||
events = round.Fail(fmt.Errorf(reason))
|
||||
reason := fmt.Errorf("some valid reason")
|
||||
events = round.Fail(reason)
|
||||
require.Len(t, events, 1)
|
||||
require.False(t, round.IsStarted())
|
||||
require.False(t, round.IsEnded())
|
||||
@@ -519,9 +519,9 @@ func testFail(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
require.Exactly(t, round.Id, event.Id)
|
||||
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)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
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 {
|
||||
BuildPoolTx(wallet WalletService, payments []domain.Payment) (poolTx string, err error)
|
||||
BuildCongestionTree(poolTx string, payments []domain.Payment) (congestionTree domain.CongestionTree, err error)
|
||||
BuildForfeitTxs(poolTx string, payments []domain.Payment) (connectors []string, forfeitTxs []string, err error)
|
||||
BuildPoolTx(
|
||||
aspPubkey *secp256k1.PublicKey, wallet WalletService, payments []domain.Payment,
|
||||
) (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)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ type WalletService interface {
|
||||
) (string, error)
|
||||
Transfer(ctx context.Context, outs []TxOutput) (string, error)
|
||||
BroadcastTransaction(ctx context.Context, txHex string) (string, error)
|
||||
Close()
|
||||
}
|
||||
|
||||
type WalletStatus interface {
|
||||
@@ -33,5 +34,6 @@ type TxInput interface {
|
||||
|
||||
type TxOutput interface {
|
||||
GetAmount() uint64
|
||||
GetAsset() string
|
||||
GetScript() string
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/timshannon/badgerhold/v4"
|
||||
)
|
||||
|
||||
const roundStoreDir = "rounds"
|
||||
|
||||
type roundRepository struct {
|
||||
store *badgerhold.Store
|
||||
}
|
||||
@@ -33,7 +35,7 @@ func NewRoundRepository(config ...interface{}) (dbtypes.RoundStore, error) {
|
||||
|
||||
var dir string
|
||||
if len(baseDir) > 0 {
|
||||
dir = filepath.Join(baseDir, eventStoreDir)
|
||||
dir = filepath.Join(baseDir, roundStoreDir)
|
||||
}
|
||||
store, err := createDB(dir, logger)
|
||||
if err != nil {
|
||||
@@ -58,7 +60,7 @@ func (r *roundRepository) GetCurrentRound(
|
||||
return nil, err
|
||||
}
|
||||
if len(rounds) <= 0 {
|
||||
return nil, nil
|
||||
return nil, fmt.Errorf("ongoing round not found")
|
||||
}
|
||||
return &rounds[0], nil
|
||||
}
|
||||
|
||||
@@ -82,36 +82,32 @@ func serializeEvent(event domain.RoundEvent) ([]byte, error) {
|
||||
|
||||
func deserializeEvent(buf []byte) (domain.RoundEvent, error) {
|
||||
{
|
||||
var event = domain.RoundStarted{}
|
||||
if err := json.Unmarshal(buf, &event); err == nil {
|
||||
var event = domain.RoundFailed{}
|
||||
if err := json.Unmarshal(buf, &event); err == nil && len(event.Err) > 0 {
|
||||
return event, nil
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var event = domain.RoundFinalizationStarted{}
|
||||
if err := json.Unmarshal(buf, &event); err == nil {
|
||||
return event, nil
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var event = domain.RoundFailed{}
|
||||
if err := json.Unmarshal(buf, &event); err == nil {
|
||||
var event = domain.RoundFinalizationStarted{}
|
||||
if err := json.Unmarshal(buf, &event); err == nil && len(event.CongestionTree) > 0 {
|
||||
return event, nil
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/timshannon/badgerhold/v4"
|
||||
)
|
||||
|
||||
const vtxoStoreDir = "vtxos"
|
||||
|
||||
type vtxoRepository struct {
|
||||
store *badgerhold.Store
|
||||
}
|
||||
@@ -33,7 +35,7 @@ func NewVtxoRepository(config ...interface{}) (dbtypes.VtxoStore, error) {
|
||||
|
||||
var dir string
|
||||
if len(baseDir) > 0 {
|
||||
dir = filepath.Join(baseDir, eventStoreDir)
|
||||
dir = filepath.Join(baseDir, vtxoStoreDir)
|
||||
}
|
||||
store, err := createDB(dir, logger)
|
||||
if err != nil {
|
||||
|
||||
@@ -138,7 +138,8 @@ func testRoundEventRepository(t *testing.T, svc ports.RepoManager) {
|
||||
handler: func(round *domain.Round) {
|
||||
require.NotNil(t, round)
|
||||
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)
|
||||
},
|
||||
},
|
||||
@@ -274,7 +275,7 @@ func testRoundRepository(t *testing.T, svc ports.RepoManager) {
|
||||
require.NoError(t, err)
|
||||
|
||||
currentRound, err = svc.Rounds().GetCurrentRound(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, currentRound)
|
||||
|
||||
roundById, err = svc.Rounds().GetRoundWithId(ctx, roundId)
|
||||
|
||||
@@ -68,6 +68,7 @@ func (l outputList) toProto() []*pb.Output {
|
||||
list = append(list, &pb.Output{
|
||||
Amount: out.GetAmount(),
|
||||
Script: out.GetScript(),
|
||||
Asset: out.GetAsset(),
|
||||
})
|
||||
}
|
||||
return list
|
||||
|
||||
@@ -26,9 +26,9 @@ func (s *service) Stop() {
|
||||
|
||||
func (s *service) ScheduleTask(interval int64, immediate bool, task func()) error {
|
||||
if immediate {
|
||||
_, err := s.scheduler.Every(interval).Seconds().Do(task)
|
||||
_, err := s.scheduler.Every(int(interval)).Seconds().Do(task)
|
||||
return err
|
||||
}
|
||||
_, err := s.scheduler.Every(interval).Seconds().WaitForSchedule().Do(task)
|
||||
_, err := s.scheduler.Every(int(interval)).Seconds().WaitForSchedule().Do(task)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/ark-network/ark/internal/core/domain"
|
||||
"github.com/ark-network/ark/internal/core/ports"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/vulpemventures/go-elements/network"
|
||||
"github.com/vulpemventures/go-elements/psetv2"
|
||||
"github.com/vulpemventures/go-elements/transaction"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -17,31 +17,18 @@ const (
|
||||
)
|
||||
|
||||
type txBuilder struct {
|
||||
net *network.Network
|
||||
aspPublicKey *secp256k1.PublicKey
|
||||
net network.Network
|
||||
}
|
||||
|
||||
func toElementsNetwork(net common.Network) *network.Network {
|
||||
switch 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),
|
||||
}
|
||||
func NewTxBuilder(net network.Network) ports.TxBuilder {
|
||||
return &txBuilder{net}
|
||||
}
|
||||
|
||||
// BuildCongestionTree implements ports.TxBuilder.
|
||||
func (b *txBuilder) BuildCongestionTree(poolTx string, payments []domain.Payment) (congestionTree domain.CongestionTree, err error) {
|
||||
poolTxID, err := getTxID(poolTx)
|
||||
func (b *txBuilder) BuildCongestionTree(
|
||||
aspPubkey *secp256k1.PublicKey, poolTx string, payments []domain.Payment,
|
||||
) (congestionTree domain.CongestionTree, err error) {
|
||||
poolTxID, err := getTxid(poolTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -49,7 +36,7 @@ func (b *txBuilder) BuildCongestionTree(poolTx string, payments []domain.Payment
|
||||
receivers := receiversFromPayments(payments)
|
||||
|
||||
return buildCongestionTree(
|
||||
newOutputScriptFactory(b.aspPublicKey, b.net),
|
||||
newOutputScriptFactory(aspPubkey, b.net),
|
||||
b.net,
|
||||
poolTxID,
|
||||
receivers,
|
||||
@@ -57,13 +44,15 @@ func (b *txBuilder) BuildCongestionTree(poolTx string, payments []domain.Payment
|
||||
}
|
||||
|
||||
// BuildForfeitTxs implements ports.TxBuilder.
|
||||
func (b *txBuilder) BuildForfeitTxs(poolTx string, payments []domain.Payment) (connectors []string, forfeitTxs []string, err error) {
|
||||
poolTxID, err := getTxID(poolTx)
|
||||
func (b *txBuilder) BuildForfeitTxs(
|
||||
aspPubkey *secp256k1.PublicKey, poolTx string, payments []domain.Payment,
|
||||
) (connectors []string, forfeitTxs []string, err error) {
|
||||
poolTxID, err := getTxid(poolTx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
aspScript, err := p2wpkhScript(b.aspPublicKey, b.net)
|
||||
aspScript, err := p2wpkhScript(aspPubkey, b.net)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -117,8 +106,10 @@ func (b *txBuilder) BuildForfeitTxs(poolTx string, payments []domain.Payment) (c
|
||||
}
|
||||
|
||||
// BuildPoolTx implements ports.TxBuilder.
|
||||
func (b *txBuilder) BuildPoolTx(wallet ports.WalletService, payments []domain.Payment) (poolTx string, err error) {
|
||||
aspScriptBytes, err := p2wpkhScript(b.aspPublicKey, b.net)
|
||||
func (b *txBuilder) BuildPoolTx(
|
||||
aspPubkey *secp256k1.PublicKey, wallet ports.WalletService, payments []domain.Payment,
|
||||
) (poolTx string, err error) {
|
||||
aspScriptBytes, err := p2wpkhScript(aspPubkey, b.net)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -134,41 +125,45 @@ func (b *txBuilder) BuildPoolTx(wallet ports.WalletService, payments []domain.Pa
|
||||
ctx := context.Background()
|
||||
|
||||
return wallet.Transfer(ctx, []ports.TxOutput{
|
||||
newOutput(aspScript, sharedOutputAmount),
|
||||
newOutput(aspScript, connectorOutputAmount),
|
||||
newOutput(aspScript, sharedOutputAmount, b.net.AssetID),
|
||||
newOutput(aspScript, connectorOutputAmount, b.net.AssetID),
|
||||
})
|
||||
}
|
||||
|
||||
func connectorsToInputArgs(connectors []string) ([]psetv2.InputArgs, error) {
|
||||
inputs := make([]psetv2.InputArgs, 0, len(connectors)+1)
|
||||
for i, psetb64 := range connectors {
|
||||
txID, err := getTxID(psetb64)
|
||||
tx, err := psetv2.NewPsetFromBase64(psetb64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
input := psetv2.InputArgs{
|
||||
Txid: txID,
|
||||
TxIndex: 0,
|
||||
utx, err := tx.UnsignedTx()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inputs = append(inputs, input)
|
||||
|
||||
if i == len(connectors)-1 {
|
||||
input := psetv2.InputArgs{
|
||||
Txid: txID,
|
||||
TxIndex: 1,
|
||||
txid := utx.TxHash().String()
|
||||
for j := range tx.Outputs {
|
||||
inputs = append(inputs, psetv2.InputArgs{
|
||||
Txid: txid,
|
||||
TxIndex: uint32(j),
|
||||
})
|
||||
if i != len(connectors)-1 {
|
||||
break
|
||||
}
|
||||
inputs = append(inputs, input)
|
||||
}
|
||||
}
|
||||
return inputs, nil
|
||||
}
|
||||
|
||||
func getTxID(psetBase64 string) (string, error) {
|
||||
pset, err := psetv2.NewPsetFromBase64(psetBase64)
|
||||
func getTxid(txStr string) (string, error) {
|
||||
pset, err := psetv2.NewPsetFromBase64(txStr)
|
||||
if err != nil {
|
||||
tx, err := transaction.NewTxFromHex(txStr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tx.TxHash().String(), nil
|
||||
}
|
||||
|
||||
utx, err := pset.UnsignedTx()
|
||||
if err != nil {
|
||||
@@ -205,12 +200,14 @@ func sumReceivers(receivers []domain.Receiver) uint64 {
|
||||
type output struct {
|
||||
script string
|
||||
amount uint64
|
||||
asset string
|
||||
}
|
||||
|
||||
func newOutput(script string, amount uint64) ports.TxOutput {
|
||||
func newOutput(script string, amount uint64, asset string) ports.TxOutput {
|
||||
return &output{
|
||||
script: script,
|
||||
amount: amount,
|
||||
asset: asset,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +215,10 @@ func (o *output) GetAmount() uint64 {
|
||||
return o.amount
|
||||
}
|
||||
|
||||
func (o *output) GetAsset() string {
|
||||
return o.asset
|
||||
}
|
||||
|
||||
func (o *output) GetScript() string {
|
||||
return o.script
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
txbuilder "github.com/ark-network/ark/internal/infrastructure/tx-builder/dummy"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/vulpemventures/go-elements/address"
|
||||
"github.com/vulpemventures/go-elements/network"
|
||||
"github.com/vulpemventures/go-elements/payment"
|
||||
"github.com/vulpemventures/go-elements/psetv2"
|
||||
@@ -20,12 +19,7 @@ const (
|
||||
)
|
||||
|
||||
func createTestTxBuilder() (ports.TxBuilder, error) {
|
||||
_, key, err := common.DecodePubKey(testingKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return txbuilder.NewTxBuilder(key, common.MainNet), nil
|
||||
return txbuilder.NewTxBuilder(network.Liquid), nil
|
||||
}
|
||||
|
||||
func createTestPoolTx(sharedOutputAmount, numberOfInputs uint64) (string, error) {
|
||||
@@ -34,16 +28,8 @@ func createTestPoolTx(sharedOutputAmount, numberOfInputs uint64) (string, error)
|
||||
return "", err
|
||||
}
|
||||
|
||||
payment := payment.FromPublicKey(key, &network.Regtest, nil)
|
||||
addr, err := payment.WitnessPubKeyHash()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
script, err := address.ToOutputScript(addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
payment := payment.FromPublicKey(key, &network.Testnet, nil)
|
||||
script := payment.WitnessScript
|
||||
|
||||
pset, err := psetv2.New(nil, nil, nil)
|
||||
if err != nil {
|
||||
@@ -108,6 +94,7 @@ func TestBuildCongestionTree(t *testing.T) {
|
||||
fixtures := []struct {
|
||||
payments []domain.Payment
|
||||
expectedNodesNum int // 2*len(receivers)-1
|
||||
expectedLeavesNum int
|
||||
}{
|
||||
{
|
||||
payments: []domain.Payment{
|
||||
@@ -120,24 +107,25 @@ func TestBuildCongestionTree(t *testing.T) {
|
||||
VOut: 0,
|
||||
},
|
||||
Receiver: domain.Receiver{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
},
|
||||
},
|
||||
Receivers: []domain.Receiver{
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 400,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedNodesNum: 3,
|
||||
expectedLeavesNum: 2,
|
||||
},
|
||||
{
|
||||
payments: []domain.Payment{
|
||||
@@ -150,18 +138,18 @@ func TestBuildCongestionTree(t *testing.T) {
|
||||
VOut: 0,
|
||||
},
|
||||
Receiver: domain.Receiver{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
},
|
||||
},
|
||||
Receivers: []domain.Receiver{
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 400,
|
||||
},
|
||||
},
|
||||
@@ -175,18 +163,18 @@ func TestBuildCongestionTree(t *testing.T) {
|
||||
VOut: 0,
|
||||
},
|
||||
Receiver: domain.Receiver{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
},
|
||||
},
|
||||
Receivers: []domain.Receiver{
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 400,
|
||||
},
|
||||
},
|
||||
@@ -200,31 +188,37 @@ func TestBuildCongestionTree(t *testing.T) {
|
||||
VOut: 0,
|
||||
},
|
||||
Receiver: domain.Receiver{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
},
|
||||
},
|
||||
Receivers: []domain.Receiver{
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 400,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedNodesNum: 11,
|
||||
expectedLeavesNum: 6,
|
||||
},
|
||||
}
|
||||
|
||||
_, key, err := common.DecodePubKey(testingKey)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
|
||||
for _, f := range fixtures {
|
||||
tree, err := builder.BuildCongestionTree(poolTx, f.payments)
|
||||
tree, err := builder.BuildCongestionTree(key, poolTx, f.payments)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, f.expectedNodesNum, tree.NumberOfNodes())
|
||||
require.Len(t, tree.Leaves(), f.expectedLeavesNum)
|
||||
|
||||
// check the root
|
||||
require.Len(t, tree[0], 1)
|
||||
@@ -298,7 +292,7 @@ func TestBuildForfeitTxs(t *testing.T) {
|
||||
VOut: 0,
|
||||
},
|
||||
Receiver: domain.Receiver{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
},
|
||||
@@ -308,18 +302,18 @@ func TestBuildForfeitTxs(t *testing.T) {
|
||||
VOut: 1,
|
||||
},
|
||||
Receiver: domain.Receiver{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 400,
|
||||
},
|
||||
},
|
||||
},
|
||||
Receivers: []domain.Receiver{
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 600,
|
||||
},
|
||||
{
|
||||
Pubkey: "apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x",
|
||||
Pubkey: "020000000000000000000000000000000000000000000000000000000000000002",
|
||||
Amount: 400,
|
||||
},
|
||||
},
|
||||
@@ -330,10 +324,15 @@ func TestBuildForfeitTxs(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for _, f := range fixtures {
|
||||
connectors, forfeitTxs, err := builder.BuildForfeitTxs(poolTx, f.payments)
|
||||
_, key, err := common.DecodePubKey(testingKey)
|
||||
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, forfeitTxs, f.expectedNumOfForfeitTxs)
|
||||
|
||||
|
||||
@@ -16,6 +16,34 @@ func createConnectors(
|
||||
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
|
||||
remainingAmount := connectorAmount * numberOfConnectors
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ func createForfeitTx(
|
||||
vtxoInput psetv2.InputArgs,
|
||||
vtxoAmount uint64,
|
||||
aspScript []byte,
|
||||
net *network.Network,
|
||||
net network.Network,
|
||||
) (forfeitTx string, err error) {
|
||||
pset, err := psetv2.New(nil, nil, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package txbuilder
|
||||
|
||||
import (
|
||||
"github.com/ark-network/ark/common"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/ark-network/ark/internal/core/domain"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
@@ -17,8 +18,8 @@ const (
|
||||
|
||||
type outputScriptFactory func(leaves []domain.Receiver) ([]byte, error)
|
||||
|
||||
func p2wpkhScript(publicKey *secp256k1.PublicKey, net *network.Network) ([]byte, error) {
|
||||
payment := payment.FromPublicKey(publicKey, net, nil)
|
||||
func p2wpkhScript(publicKey *secp256k1.PublicKey, net network.Network) ([]byte, error) {
|
||||
payment := payment.FromPublicKey(publicKey, &net, nil)
|
||||
addr, err := payment.WitnessPubKeyHash()
|
||||
if err != nil {
|
||||
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.
|
||||
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) {
|
||||
aspScript, err := p2wpkhScript(aspPublicKey, net)
|
||||
if err != nil {
|
||||
@@ -39,7 +40,11 @@ func newOutputScriptFactory(aspPublicKey *secp256k1.PublicKey, net *network.Netw
|
||||
case 0:
|
||||
return nil, nil
|
||||
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 {
|
||||
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)
|
||||
func buildCongestionTree(
|
||||
createOutputScript outputScriptFactory,
|
||||
net *network.Network,
|
||||
net network.Network,
|
||||
poolTxID string,
|
||||
receivers []domain.Receiver,
|
||||
) (congestionTree domain.CongestionTree, err error) {
|
||||
@@ -108,6 +113,7 @@ func buildCongestionTree(
|
||||
Txid: txid,
|
||||
Tx: psetB64,
|
||||
ParentTxid: parentTxid,
|
||||
Leaf: psetWithLevel.leaf,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -138,13 +144,13 @@ type node struct {
|
||||
left *node
|
||||
right *node
|
||||
createOutputScript outputScriptFactory
|
||||
network *network.Network
|
||||
network network.Network
|
||||
}
|
||||
|
||||
// create a node from a single receiver
|
||||
func newLeaf(
|
||||
createOutputScript outputScriptFactory,
|
||||
network *network.Network,
|
||||
network network.Network,
|
||||
receiver domain.Receiver,
|
||||
) *node {
|
||||
return &node{
|
||||
@@ -172,7 +178,7 @@ func newBranch(
|
||||
|
||||
// is it the final node of the tree
|
||||
func (n *node) isLeaf() bool {
|
||||
return len(n.receivers) == 1
|
||||
return n.left == nil && n.right == nil
|
||||
}
|
||||
|
||||
// compute the output amount of a node
|
||||
@@ -256,6 +262,7 @@ func (n *node) pset(input psetv2.InputArgs) (*psetv2.Pset, error) {
|
||||
type psetWithLevel struct {
|
||||
pset *psetv2.Pset
|
||||
level int
|
||||
leaf bool
|
||||
}
|
||||
|
||||
// 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{
|
||||
{pset, level},
|
||||
{pset, level, n.isLeaf()},
|
||||
}
|
||||
|
||||
if n.isLeaf() {
|
||||
|
||||
46
asp/internal/interface/grpc/config.go
Normal file
46
asp/internal/interface/grpc/config.go
Normal 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
|
||||
}
|
||||
@@ -7,7 +7,6 @@ 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/domain"
|
||||
"github.com/ark-network/ark/internal/core/ports"
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
@@ -25,7 +24,7 @@ type handler struct {
|
||||
listeners []*listener
|
||||
}
|
||||
|
||||
func NewHandler(service application.Service, repoManager ports.RepoManager) arkv1.ArkServiceServer {
|
||||
func NewHandler(service application.Service) arkv1.ArkServiceServer {
|
||||
h := &handler{
|
||||
svc: service,
|
||||
listenersLock: &sync.Mutex{},
|
||||
@@ -154,6 +153,9 @@ func (h *handler) GetEventStream(_ *arkv1.GetEventStreamRequest, stream arkv1.Ar
|
||||
|
||||
switch ev.Event.(type) {
|
||||
case *arkv1.GetEventStreamResponse_RoundFinalized, *arkv1.GetEventStreamResponse_RoundFailed:
|
||||
if err := stream.Send(ev); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -220,7 +222,7 @@ func (h *handler) listenToEvents() {
|
||||
Id: e.Id,
|
||||
PoolPartialTx: e.PoolTx,
|
||||
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{
|
||||
RoundFailed: &arkv1.RoundFailed{
|
||||
Id: e.Id,
|
||||
Reason: e.Err.Error(),
|
||||
Reason: e.Err,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/ark-network/ark/common"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/vulpemventures/go-elements/psetv2"
|
||||
)
|
||||
|
||||
@@ -20,14 +20,13 @@ func parseTxs(txs []string) ([]string, error) {
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
func parseAddress(addr string) (string, error) {
|
||||
func parseAddress(addr string) (*secp256k1.PublicKey, error) {
|
||||
if len(addr) <= 0 {
|
||||
return "", fmt.Errorf("missing address")
|
||||
return nil, fmt.Errorf("missing address")
|
||||
}
|
||||
_, userPubkey, _, err := common.DecodeAddress(addr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid address: %s", err)
|
||||
return nil, fmt.Errorf("invalid address: %s", err)
|
||||
}
|
||||
pubkey := hex.EncodeToString(userPubkey.SerializeCompressed())
|
||||
return pubkey, nil
|
||||
return userPubkey, nil
|
||||
}
|
||||
|
||||
16
asp/internal/interface/grpc/interceptors/interceptor.go
Normal file
16
asp/internal/interface/grpc/interceptors/interceptor.go
Normal 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))
|
||||
}
|
||||
28
asp/internal/interface/grpc/interceptors/logger.go
Normal file
28
asp/internal/interface/grpc/interceptors/logger.go
Normal 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)
|
||||
}
|
||||
63
asp/internal/interface/grpc/service.go
Normal file
63
asp/internal/interface/grpc/service.go
Normal 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")
|
||||
}
|
||||
@@ -1,49 +1,6 @@
|
||||
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 {
|
||||
Start() error
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@ func getConn(ctx *cli.Context) (*grpc.ClientConn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpcUrl, ok := state["rpc_url"]
|
||||
rpcUrl, ok := state["ark_url"]
|
||||
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()))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@@ -47,6 +48,14 @@ func faucetAction(ctx *cli.Context) error {
|
||||
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 {
|
||||
return fmt.Errorf("faucet failed: %s", event.GetRoundFailed().GetReason())
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ require (
|
||||
require (
|
||||
github.com/btcsuite/btcd/btcutil v1.1.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/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
|
||||
21
noah/go.sum
21
noah/go.sum
@@ -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/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/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.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=
|
||||
@@ -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 v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
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/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/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-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.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
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-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-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-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/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-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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-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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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/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/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-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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4 h1:W12Pwm4urIbRdGhMEg2NM9O3TWKjNcxQhs46V0ypf/k=
|
||||
|
||||
16
noah/send.go
16
noah/send.go
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -16,7 +17,7 @@ import (
|
||||
|
||||
type receiver struct {
|
||||
To string `json:"to"`
|
||||
Amount int64 `json:"amount"`
|
||||
Amount uint64 `json:"amount"`
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -55,7 +56,6 @@ func sendAction(ctx *cli.Context) error {
|
||||
|
||||
receiversOutput := make([]*arkv1.Output, 0)
|
||||
sumOfReceivers := uint64(0)
|
||||
net := getNetwork()
|
||||
|
||||
for _, receiver := range receiversJSON {
|
||||
_, 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)
|
||||
}
|
||||
|
||||
encodedKey, err := common.EncodePubKey(net.PubKey, userKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encodedKey := hex.EncodeToString(userKey.SerializeCompressed())
|
||||
receiversOutput = append(receiversOutput, &arkv1.Output{
|
||||
Pubkey: encodedKey,
|
||||
Amount: uint64(receiver.Amount),
|
||||
})
|
||||
sumOfReceivers += receiver.Amount
|
||||
}
|
||||
client, close, err := getArkClient(ctx)
|
||||
if err != nil {
|
||||
@@ -104,10 +101,7 @@ func sendAction(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
walletPubKey := walletPrvKey.PubKey()
|
||||
encodedPubKey, err := common.EncodePubKey(net.PubKey, walletPubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encodedPubKey := hex.EncodeToString(walletPubKey.SerializeCompressed())
|
||||
|
||||
changeReceiver := &arkv1.Output{
|
||||
Pubkey: encodedPubKey,
|
||||
|
||||
Reference in New Issue
Block a user