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
@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

View File

@@ -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)
}

View File

@@ -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

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/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=

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 (
"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")
}
}

View File

@@ -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)
if err != nil {
return "", err
}
serializedPubkey, err := common.EncodePubKey(s.network.PubKey, pubkey)
if err != nil {
return "", err
}
s.pubkey = serializedPubkey
pubkey, err := common.EncodePubKey(s.network.PubKey, s.pubkey)
if err != nil {
return "", err
}
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
}
}

View File

@@ -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
}

View File

@@ -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 {

View File

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

View File

@@ -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)

View File

@@ -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)
})
})

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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

View File

@@ -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
}

View File

@@ -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,40 +125,44 @@ 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 {
return "", err
tx, err := transaction.NewTxFromHex(txStr)
if err != nil {
return "", err
}
return tx.TxHash().String(), nil
}
utx, err := pset.UnsignedTx()
@@ -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
}

View File

@@ -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 {
@@ -106,8 +92,9 @@ func TestBuildCongestionTree(t *testing.T) {
poolTxID := poolTxUnsigned.TxHash().String()
fixtures := []struct {
payments []domain.Payment
expectedNodesNum int // 2*len(receivers)-1
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,
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,
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)
require.NoError(t, err)
_, 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)

View File

@@ -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

View File

@@ -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 {

View File

@@ -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() {

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"
"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,
},
},
}

View File

@@ -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
}

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
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()
}

View File

@@ -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()))

View File

@@ -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())
}

View File

@@ -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

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/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=

View File

@@ -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,