From d184fc0f41aa2d657c775979648da8c2d0f68c16 Mon Sep 17 00:00:00 2001 From: Dusan Sekulic Date: Fri, 22 Nov 2024 15:31:20 +0100 Subject: [PATCH] [SDK] E2E test for WASM wrapper (#378) * wasm e2e test * Remove ark-sdk.wasm.gz from repository * pr review * exclude test files from linting * fix * test fix * go work sync * gha fix * gha fix * wasm e2e test * kill webserver * Fix nonce encoding/decoding & Fix pop from queue of payment requests (#375) * bug fix - paymentMap pop input traversal * bug fix - nonce encode/decode * pr review * pr review * Fix trivy gh action (#381) * Update trivy gha * Update tryvy gha * Fix * merge * Panic recovery in app svc (#372) * panic recovery * pr review * Support connecting to bitcoind via ZMQ (#286) * add ZMQ env vars * consolidate config and app-config naming * [Server] Validate forfeit txs without re-building them (#382) * compute forfeit partial tx client-side first * fix conflict * go work sync * move verify sig in VerifyForfeits * move check after len(inputs) * Hotfix: Prevent ZMQ-based bitcoin wallet to panic (#383) * Hotfix bct embedded wallet w/ ZMQ * Fixes * Rename vtxo is_oor to is_pending (#385) * Rename vtxo is_oor > is_pending * Clean swaggers * Change representation of taproot trees & Internal fixes (#384) * migrate descriptors --> tapscripts * fix covenantless * dynamic boarding exit delay * remove duplicates in tree and bitcointree * agnostic signatures validation * revert GetInfo change * renaming VtxoScript var * Agnostic script server (#6) * Hotfix: Prevent ZMQ-based bitcoin wallet to panic (#383) * Hotfix bct embedded wallet w/ ZMQ * Fixes * Rename vtxo is_oor to is_pending (#385) * Rename vtxo is_oor > is_pending * Clean swaggers * Revert changes to client and sdk * descriptor in oneof * support CHECKSIG_ADD in MultisigClosure * use right witness size in OOR tx fee estimation * Revert changes --------- Co-authored-by: Pietralberto Mazza <18440657+altafan@users.noreply.github.com> * fix unit test * fix unit test * fix unit test --------- Co-authored-by: Pietralberto Mazza <18440657+altafan@users.noreply.github.com> Co-authored-by: Marco Argentieri <3596602+tiero@users.noreply.github.com> Co-authored-by: Louis Singer <41042567+louisinger@users.noreply.github.com> --- .github/workflows/ark.unit.yaml | 2 +- .github/workflows/ark.wasm_test.yaml | 37 ++ go.work.sum | 8 +- pkg/client-sdk/Makefile | 17 +- pkg/client-sdk/go.mod | 7 + pkg/client-sdk/go.sum | 36 ++ pkg/client-sdk/test/wasm/wasm_test.go | 569 ++++++++++++++++++++++++ pkg/client-sdk/test/wasm/web/index.html | 20 + 8 files changed, 690 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/ark.wasm_test.yaml create mode 100644 pkg/client-sdk/test/wasm/wasm_test.go create mode 100644 pkg/client-sdk/test/wasm/web/index.html diff --git a/.github/workflows/ark.unit.yaml b/.github/workflows/ark.unit.yaml index 91e91d50d..c96782b77 100755 --- a/.github/workflows/ark.unit.yaml +++ b/.github/workflows/ark.unit.yaml @@ -78,7 +78,7 @@ jobs: with: version: v1.61 working-directory: ./pkg/client-sdk - args: --timeout 5m + args: --timeout 5m --skip-files=.*_test.go - name: check code integrity uses: securego/gosec@master with: diff --git a/.github/workflows/ark.wasm_test.yaml b/.github/workflows/ark.wasm_test.yaml new file mode 100644 index 000000000..bb97ac02b --- /dev/null +++ b/.github/workflows/ark.wasm_test.yaml @@ -0,0 +1,37 @@ +name: wasm_test + +on: + push: + branches: + - master + pull_request: + branches: + - '**' + +jobs: + test: + name: wasm integration tests + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./pkg/client-sdk + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-go@v4 + with: + go-version: '>=1.23.1' + + - name: Run go work sync + run: go work sync + + - name: Install Python + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Run Nigiri + uses: vulpemventures/nigiri-github-action@v1 + + - name: wasm test + run: make test-wasm \ No newline at end of file diff --git a/go.work.sum b/go.work.sum index 31f0d5368..f93c45513 100644 --- a/go.work.sum +++ b/go.work.sum @@ -501,6 +501,8 @@ github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnTh github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/cockroach-go/v2 v2.1.1 h1:3XzfSMuUT0wBe1a3o5C0eOTcArhmmFAg2Jzh/7hhKqo= github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM= +github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= +github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= @@ -514,9 +516,7 @@ github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369 h1:XNT/Zf5l++1Pyg08 github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= -github.com/dgraph-io/badger/v4 v4.3.0/go.mod h1:Sc0T595g8zqAQRDf44n+z3wG4BOqLwceaFntt8KPxUM= github.com/dgraph-io/ristretto v0.1.2-0.20240116140435-c67e07994f91/go.mod h1:swkazRqnUf1N62d0Nutz7KIj2UKqsm/H8tD0nBJAXqM= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -600,6 +600,8 @@ github.com/greatroar/blobloom v0.8.0/go.mod h1:mjMJ1hh1wjGVfr93QIHJ6FfDNVrA0IELv github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= +github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= @@ -736,6 +738,8 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3 github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/orisano/pixelmatch v0.0.0-20230914042517-fa304d1dc785 h1:J1//5K/6QF10cZ59zLcVNFGmBfiSrH8Cho/lNrViK9s= +github.com/orisano/pixelmatch v0.0.0-20230914042517-fa304d1dc785/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pierrec/lz4/v4 v4.1.16 h1:kQPfno+wyx6C5572ABwV+Uo3pDFzQ7yhyGchSyRda0c= github.com/pierrec/lz4/v4 v4.1.16/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= diff --git a/pkg/client-sdk/Makefile b/pkg/client-sdk/Makefile index ff4951c96..890d2bbb8 100644 --- a/pkg/client-sdk/Makefile +++ b/pkg/client-sdk/Makefile @@ -1,4 +1,4 @@ -.PHONY: genrest test vet lint +.PHONY: genrest test vet lint prepare-wasm-test ## genrest: compiles rest client from stub with https://github.com/go-swagger/go-swagger genrest: @@ -8,7 +8,7 @@ genrest: ## test: runs unit tests test: @echo "Running unit tests..." - @go test -v -count=1 -race ./... + @go test -v -count=1 -race $$(go list ./... | grep -v '/test/wasm') ## vet: code analysis vet: @@ -31,4 +31,15 @@ GO_VERSION := $(shell go version | cut -d' ' -f3) build-wasm: @mkdir -p $(BUILD_DIR) @echo "Version: $(VERSION)" - @GOOS=js GOARCH=wasm GO111MODULE=on go build -ldflags="-X 'main.Version=$(VERSION)'" -o $(BUILD_DIR)/ark-sdk.wasm $(WASM_DIR)/main.go + @GOOS=js GOARCH=wasm GO111MODULE=on go build -ldflags="-s -w -X 'main.Version=$(VERSION)'" -o $(BUILD_DIR)/ark-sdk.wasm $(WASM_DIR)/main.go + +test-wasm: + $(MAKE) build-wasm BUILD_DIR=./test/wasm/web + @echo "Copying $(go env GOROOT)/misc/wasm/wasm_exec.js" + @cp `go env GOROOT`/misc/wasm/wasm_exec.js ./test/wasm/web + @echo "Starting web server..." + @cd ./test/wasm/web && python3 -m http.server 8000 & + @echo "Waiting for server to start..." + @sleep 3 + @echo "Running tests..." + @cd ./test/wasm && go test -v \ No newline at end of file diff --git a/pkg/client-sdk/go.mod b/pkg/client-sdk/go.mod index 3c0c5300d..6a27440df 100644 --- a/pkg/client-sdk/go.mod +++ b/pkg/client-sdk/go.mod @@ -19,6 +19,8 @@ require ( github.com/go-openapi/swag v0.23.0 github.com/go-openapi/validate v0.24.0 github.com/lightningnetwork/lnd v0.18.2-beta + github.com/playwright-community/playwright-go v0.4802.0 + github.com/shirou/gopsutil v3.21.11+incompatible github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 github.com/timshannon/badgerhold/v4 v4.0.3 @@ -37,18 +39,22 @@ require ( github.com/btcsuite/winsvc v1.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect github.com/decred/dcrd/lru v1.1.3 // indirect github.com/dgraph-io/ristretto v1.0.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/analysis v0.23.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/loads v0.22.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-stack/stack v1.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -75,6 +81,7 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.etcd.io/bbolt v1.3.10 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect diff --git a/pkg/client-sdk/go.sum b/pkg/client-sdk/go.sum index ce2cfcf9f..bcd87b840 100644 --- a/pkg/client-sdk/go.sum +++ b/pkg/client-sdk/go.sum @@ -25,7 +25,9 @@ github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9 github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcwallet v0.16.10-0.20240718224643-db3a4a2543bd h1:QDb8foTCRoXrfoZVEzSYgSde16MJh4gCtCin8OCS0kI= +github.com/btcsuite/btcwallet v0.16.10-0.20240718224643-db3a4a2543bd/go.mod h1:X2xDre+j1QphTRo54y2TikUzeSvreL1t1aMXrD8Kc5A= github.com/btcsuite/btcwallet/walletdb v1.4.2 h1:zwZZ+zaHo4mK+FAN6KeK85S3oOm+92x2avsHvFAhVBE= +github.com/btcsuite/btcwallet/walletdb v1.4.2/go.mod h1:7ZQ+BvOEre90YT7eSq8bLoxTsgXidUzA/mqbRS114CQ= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= @@ -53,8 +55,11 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= @@ -63,10 +68,13 @@ github.com/decred/dcrd/lru v1.1.3 h1:w9EAbvGLyzm6jTjF83UKuqZEiUtJmvRhQDOCEIvSuE0 github.com/decred/dcrd/lru v1.1.3/go.mod h1:Tw0i0pJyiLEx/oZdHLe1Wdv/Y7EGzAX+sYftnmxBR4o= github.com/dgraph-io/badger/v4 v4.1.0/go.mod h1:P50u28d39ibBRmIJuQC/NSdBOg46HnHw7al2SW5QRHg= github.com/dgraph-io/badger/v4 v4.3.0 h1:lcsCE1/1qrRhqP+zYx6xDZb8n7U+QlwNicpc676Ub40= +github.com/dgraph-io/badger/v4 v4.3.0/go.mod h1:Sc0T595g8zqAQRDf44n+z3wG4BOqLwceaFntt8KPxUM= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgraph-io/ristretto v1.0.0 h1:SYG07bONKMlFDUYu5pEu3DGAh8c2OFNzKm6G9J4Si84= +github.com/dgraph-io/ristretto v1.0.0/go.mod h1:jTi2FiYEhQ1NsMmA7DeBykizjOuY88NhKBkepyu1jPc= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -78,11 +86,15 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= @@ -103,6 +115,8 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= 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= @@ -142,6 +156,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -178,15 +193,19 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g= +github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo= github.com/lightningnetwork/lnd v0.18.2-beta h1:Qv4xQ2ka05vqzmdkFdISHCHP6CzHoYNVKfD18XPjHsM= github.com/lightningnetwork/lnd v0.18.2-beta/go.mod h1:cGQR1cVEZFZQcCx2VBbDY8xwGjCz+SupSopU1HpjP2I= github.com/lightningnetwork/lnd/fn v1.2.1 h1:pPsVGrwi9QBwdLJzaEGK33wmiVKOxs/zc8H7+MamFf0= github.com/lightningnetwork/lnd/fn v1.2.1/go.mod h1:SyFohpVrARPKH3XVAJZlXdVe+IwMYc4OMAvrDY32kw0= github.com/lightningnetwork/lnd/tlv v1.2.6 h1:icvQG2yDr6k3ZuZzfRdG3EJp6pHurcuh3R6dg0gv/Mw= +github.com/lightningnetwork/lnd/tlv v1.2.6/go.mod h1:/CmY4VbItpOldksocmGT4lxiJqRP9oLxwSZOda2kzNQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -212,6 +231,8 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/playwright-community/playwright-go v0.4802.0 h1:FSuvi5Pg/xp+n7vFpu2wGldwSQ3grsaDlHFRfHRQiy4= +github.com/playwright-community/playwright-go v0.4802.0/go.mod h1:kBNWs/w2aJ2ZUp1wEOOFLXgOqvppFngM5OS+qyhl+ZM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -219,6 +240,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -256,7 +279,10 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= @@ -276,9 +302,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -305,6 +334,7 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -323,6 +353,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -337,18 +368,23 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/pkg/client-sdk/test/wasm/wasm_test.go b/pkg/client-sdk/test/wasm/wasm_test.go new file mode 100644 index 000000000..864d9c047 --- /dev/null +++ b/pkg/client-sdk/test/wasm/wasm_test.go @@ -0,0 +1,569 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + utils "github.com/ark-network/ark/server/test/e2e" + "github.com/playwright-community/playwright-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "io" + "net/http" + "os" + "os/exec" + "strings" + "sync" + "syscall" + "testing" + "time" + + "github.com/shirou/gopsutil/net" +) + +const ( + composePath = "../../../../docker-compose.clark.regtest.yml" +) + +func TestMain(m *testing.M) { + _, err := utils.RunCommand("docker", "compose", "-f", composePath, "up", "-d", "--build") + if err != nil { + fmt.Printf("error starting docker-compose: %s", err) + os.Exit(1) + } + + time.Sleep(10 * time.Second) + + if err := utils.GenerateBlock(); err != nil { + fmt.Printf("error generating block: %s", err) + os.Exit(1) + } + + if err := setupAspWallet(); err != nil { + fmt.Println(err) + os.Exit(1) + } + + time.Sleep(3 * time.Second) + + if err := playwright.Install(); err != nil { + fmt.Printf("error installing playwright: %v", err) + os.Exit(1) + } + + _, err = runClarkCommand("init", "--asp-url", "localhost:7070", "--password", utils.Password, "--network", "regtest", "--explorer", "http://chopsticks:3000") + if err != nil { + fmt.Printf("error initializing ark config: %s", err) + os.Exit(1) + } + + code := m.Run() + + _, err = utils.RunCommand("docker", "compose", "-f", composePath, "down", "-v") + if err != nil { + fmt.Printf("error stopping docker-compose: %s", err) + os.Exit(1) + } + + if err := killProcessByPort(8000); err != nil { + fmt.Printf("failed to kill process running on 8000, err: %v", err) + os.Exit(1) + } + + fmt.Println("killed web server running on 8000") + os.Exit(code) +} + +func TestWasm(t *testing.T) { + pw, err := playwright.Run() + require.NoError(t, err) + defer pw.Stop() + + browser, err := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{ + Headless: playwright.Bool(true), + }) + require.NoError(t, err) + defer browser.Close() + + alicePage, err := browser.NewPage() + require.NoError(t, err) + + bobPage, err := browser.NewPage() + require.NoError(t, err) + + cleanup, err := setupPages(t, []*playwright.Page{&alicePage, &bobPage}) + require.NoError(t, err) + defer cleanup() + + time.Sleep(10 * time.Second) + + t.Log("Alice is setting up her ark wallet...") + require.NoError(t, initWallet(alicePage)) + + t.Log("Bob is setting up his ark wallet...") + require.NoError(t, initWallet(bobPage)) + + time.Sleep(2 * time.Second) + + t.Log("Getting Bob's receive address...") + bobAddr, err := getReceiveAddress(bobPage) + require.NoError(t, err) + t.Logf("Bob's Offchain Address: %v\n", bobAddr.OffchainAddr) + + t.Log("Alice is acquiring onchain funds...") + aliceAddr, err := getReceiveAddress(alicePage) + require.NoError(t, err) + t.Logf("Alice's Boarding Address: %v\n", aliceAddr.BoardingAddr) + + _, err = runCommand("nigiri", "faucet", aliceAddr.BoardingAddr) + require.NoError(t, err) + + time.Sleep(3 * time.Second) + err = generateBlock() + require.NoError(t, err) + time.Sleep(2 * time.Second) + + txID, err := settle(alicePage) + require.NoError(t, err) + t.Logf("Alice onboard txID: %v", txID) + + aliceBalance, err := getBalance(alicePage) + require.NoError(t, err) + t.Logf("Alice onchain balance: %v", aliceBalance.OnchainSpendable) + t.Logf("Alice offchain balance: %v", aliceBalance.OffchainBalance) + + bobBalance, err := getBalance(bobPage) + require.NoError(t, err) + t.Logf("Bob onchain balance: %v", bobBalance.OnchainSpendable) + t.Logf("Bob offchain balance: %v", bobBalance.OffchainBalance) + + amount := 1000 + t.Logf("Alice is sending %d sats to Bob offchain...", amount) + require.NoError(t, sendAsync(alicePage, bobAddr.OffchainAddr, amount)) + + t.Log("Payment completed out of round") + + t.Logf("Bob settling the received funds...") + txID, err = settle(bobPage) + require.NoError(t, err) + t.Logf("Bob settled the received funds in round %v", txID) + + err = generateBlock() + require.NoError(t, err) + + time.Sleep(5 * time.Second) + + aliceBalance, err = getBalance(alicePage) + require.NoError(t, err) + t.Logf("Alice onchain balance: %v", aliceBalance.OnchainSpendable) + t.Logf("Alice offchain balance: %v", aliceBalance.OffchainBalance) + + bobBalance, err = getBalance(bobPage) + require.NoError(t, err) + t.Logf("Bob onchain balance: %v", bobBalance.OnchainSpendable) + t.Logf("Bob offchain balance: %v", bobBalance.OffchainBalance) + assert.Equal(t, amount, bobBalance.OffchainBalance) +} + +type Address struct { + BoardingAddr string + OffchainAddr string +} + +type Balance struct { + OnchainSpendable int + OnchainLocked int + OffchainBalance int +} + +func setupPages(t *testing.T, pages []*playwright.Page) (func(), error) { + var cleanupFuncs []func() + + for _, page := range pages { + p := *page + _, err := p.Goto("http://localhost:8000") + require.NoError(t, err) + + p.OnConsole(func(msg playwright.ConsoleMessage) { + t.Logf("console text: %v", msg.Text()) + }) + + responseCleanup := make(chan struct{}) + cleanupFuncs = append(cleanupFuncs, func() { close(responseCleanup) }) + + p.OnResponse(func(response playwright.Response) { + go func() { + select { + case <-responseCleanup: + return + default: + resp, err := response.Text() + if err != nil { + // Only log if it's not a "target closed" error + if !strings.Contains(err.Error(), "Target page, context or browser has been closed") { + t.Logf("could not get response text: %v", err) + } + return + } + t.Logf("response from %v: %v", response.URL(), resp) + } + }() + }) + + p.OnRequestFailed(func(request playwright.Request) { + t.Logf("request to %v failed", request.URL()) + }) + } + + return func() { + for _, cleanup := range cleanupFuncs { + cleanup() + } + }, nil +} + +func initWallet(page playwright.Page) error { + _, err := page.Evaluate(`async () => { + try { + const chain = "bitcoin"; + const walletType = "singlekey"; + const clientType = "rest"; + const privateKey = ""; + const password = "pass"; + const explorerUrl = ""; + const aspUrl = "http://localhost:7070"; + return await init(walletType, clientType, aspUrl, privateKey, password, chain, explorerUrl); + } catch (err) { + console.error("Init error:", err); + throw err; + } + }`) + return err +} + +func getReceiveAddress(page playwright.Page) (*Address, error) { + result, err := page.Evaluate(`async () => { + try { + return await receive(); + } catch (err) { + console.error("Receive error:", err); + throw err; + } + }`) + if err != nil { + return nil, err + } + + resultMap, ok := result.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("result is not a map") + } + + boardingAddr, ok := resultMap["boardingAddr"].(string) + if !ok { + return nil, fmt.Errorf("boardingAddr not found or not a string") + } + + offchainAddr, ok := resultMap["offchainAddr"].(string) + if !ok { + return nil, fmt.Errorf("offchainAddr not found or not a string") + } + + return &Address{ + BoardingAddr: boardingAddr, + OffchainAddr: offchainAddr, + }, nil +} + +func getBalance(page playwright.Page) (*Balance, error) { + result, err := page.Evaluate(`async () => { + try { + return await balance(false); + } catch (err) { + console.error("Error:", err); + throw err; + } + }`) + if err != nil { + return nil, err + } + + balanceMap, ok := result.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("result is not a map") + } + + onchainBalance, ok := balanceMap["onchainBalance"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("onchainBalance not found or not a map") + } + + offchainBalance, ok := balanceMap["offchainBalance"].(int) + if !ok { + return nil, fmt.Errorf("offchainBalance not found or not a int") + } + + spendable, ok := onchainBalance["spendable"].(int) + if !ok { + return nil, fmt.Errorf("spendable not found or not a int") + } + + locked, ok := onchainBalance["locked"].(int) + if !ok { + return nil, fmt.Errorf("locked not found or not a int") + } + + return &Balance{ + OnchainSpendable: spendable, + OnchainLocked: locked, + OffchainBalance: offchainBalance, + }, nil +} + +func settle(page playwright.Page) (string, error) { + result, err := page.Evaluate(`async () => { + try { + await unlock("pass"); + return await settle(); + } catch (err) { + console.error("Error:", err); + throw err; + } + }`) + if err != nil { + return "", err + } + return fmt.Sprint(result), nil +} + +func sendAsync(page playwright.Page, addr string, amount int) error { + _, err := page.Evaluate(fmt.Sprintf(`async () => { + try { + return await sendAsync(false, [{To:"%s", Amount:%d}]); + } catch (err) { + console.error("Error:", err); + throw err; + } + }`, addr, amount)) + return err +} + +func runCommand(name string, arg ...string) (string, error) { + errb := new(strings.Builder) + cmd := newCommand(name, arg...) + + stdout, err := cmd.StdoutPipe() + if err != nil { + return "", err + } + + stderr, err := cmd.StderrPipe() + if err != nil { + return "", err + } + + if err := cmd.Start(); err != nil { + return "", err + } + output := new(strings.Builder) + errorb := new(strings.Builder) + + var wg sync.WaitGroup + wg.Add(2) + + go func() { + defer wg.Done() + if _, err := io.Copy(output, stdout); err != nil { + fmt.Fprintf(errb, "error reading stdout: %s", err) + } + }() + + go func() { + defer wg.Done() + if _, err := io.Copy(errorb, stderr); err != nil { + fmt.Fprintf(errb, "error reading stderr: %s", err) + } + }() + + wg.Wait() + if err := cmd.Wait(); err != nil { + if errMsg := errorb.String(); len(errMsg) > 0 { + return "", fmt.Errorf("%s", errMsg) + } + + if outMsg := output.String(); len(outMsg) > 0 { + return "", fmt.Errorf("%s", outMsg) + } + + return "", err + } + + if errMsg := errb.String(); len(errMsg) > 0 { + return "", fmt.Errorf("%s", errMsg) + } + + return strings.Trim(output.String(), "\n"), nil +} +func newCommand(name string, arg ...string) *exec.Cmd { + cmd := exec.Command(name, arg...) + return cmd +} + +func generateBlock() error { + if _, err := runCommand("nigiri", "rpc", "generatetoaddress", "1", "bcrt1qgqsguk6wax7ynvav4zys5x290xftk49h5agg0l"); err != nil { + return err + } + + time.Sleep(6 * time.Second) + return nil +} + +func setupAspWallet() error { + adminHttpClient := &http.Client{ + Timeout: 15 * time.Second, + } + + req, err := http.NewRequest("GET", "http://localhost:7070/v1/admin/wallet/seed", nil) + if err != nil { + return fmt.Errorf("failed to prepare generate seed request: %s", err) + } + req.Header.Set("Authorization", "Basic YWRtaW46YWRtaW4=") + + seedResp, err := adminHttpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to generate seed: %s", err) + } + + var seed struct { + Seed string `json:"seed"` + } + + if err := json.NewDecoder(seedResp.Body).Decode(&seed); err != nil { + return fmt.Errorf("failed to parse response: %s", err) + } + + reqBody := bytes.NewReader([]byte(fmt.Sprintf(`{"seed": "%s", "password": "%s"}`, seed.Seed, utils.Password))) + req, err = http.NewRequest("POST", "http://localhost:7070/v1/admin/wallet/create", reqBody) + if err != nil { + return fmt.Errorf("failed to prepare wallet create request: %s", err) + } + req.Header.Set("Authorization", "Basic YWRtaW46YWRtaW4=") + req.Header.Set("Content-Type", "application/json") + + if _, err := adminHttpClient.Do(req); err != nil { + return fmt.Errorf("failed to create wallet: %s", err) + } + + reqBody = bytes.NewReader([]byte(fmt.Sprintf(`{"password": "%s"}`, utils.Password))) + req, err = http.NewRequest("POST", "http://localhost:7070/v1/admin/wallet/unlock", reqBody) + if err != nil { + return fmt.Errorf("failed to prepare wallet unlock request: %s", err) + } + req.Header.Set("Authorization", "Basic YWRtaW46YWRtaW4=") + req.Header.Set("Content-Type", "application/json") + + if _, err := adminHttpClient.Do(req); err != nil { + return fmt.Errorf("failed to unlock wallet: %s", err) + } + + var status struct { + Initialized bool `json:"initialized"` + Unlocked bool `json:"unlocked"` + Synced bool `json:"synced"` + } + for { + time.Sleep(time.Second) + + req, err := http.NewRequest("GET", "http://localhost:7070/v1/admin/wallet/status", nil) + if err != nil { + return fmt.Errorf("failed to prepare status request: %s", err) + } + resp, err := adminHttpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to get status: %s", err) + } + if err := json.NewDecoder(resp.Body).Decode(&status); err != nil { + return fmt.Errorf("failed to parse status response: %s", err) + } + if status.Initialized && status.Unlocked && status.Synced { + break + } + } + + var addr struct { + Address string `json:"address"` + } + for addr.Address == "" { + time.Sleep(time.Second) + + req, err = http.NewRequest("GET", "http://localhost:7070/v1/admin/wallet/address", nil) + if err != nil { + return fmt.Errorf("failed to prepare new address request: %s", err) + } + req.Header.Set("Authorization", "Basic YWRtaW46YWRtaW4=") + + resp, err := adminHttpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to get new address: %s", err) + } + + if err := json.NewDecoder(resp.Body).Decode(&addr); err != nil { + return fmt.Errorf("failed to parse response: %s", err) + } + } + + const numberOfFaucet = 15 // must cover the liquidity needed for all tests + + for i := 0; i < numberOfFaucet; i++ { + _, err = utils.RunCommand("nigiri", "faucet", addr.Address) + if err != nil { + return fmt.Errorf("failed to fund wallet: %s", err) + } + } + + time.Sleep(5 * time.Second) + return nil +} + +func runClarkCommand(arg ...string) (string, error) { + args := append([]string{"exec", "-t", "clarkd", "ark"}, arg...) + return utils.RunCommand("docker", args...) +} + +func findProcessByPort(port uint32) (int32, error) { + connections, err := net.Connections("tcp") + if err != nil { + return 0, fmt.Errorf("failed to get network connections: %v", err) + } + + for _, conn := range connections { + if conn.Laddr.Port == uint32(port) { + return conn.Pid, nil + } + } + + return 0, fmt.Errorf("no process found using port %v", port) +} + +func killProcessByPID(pid int) error { + process, err := os.FindProcess(pid) + if err != nil { + return fmt.Errorf("failed to find process with PID %v: %v", pid, err) + } + + if err := process.Signal(syscall.SIGKILL); err != nil { + return fmt.Errorf("failed to kill process with PID %v: %v", pid, err) + } + + fmt.Printf("Successfully killed process with PID %v.\n", pid) + return nil +} + +func killProcessByPort(port int) error { + pid, err := findProcessByPort(uint32(port)) + if err != nil { + return err + } + + return killProcessByPID(int(pid)) +} diff --git a/pkg/client-sdk/test/wasm/web/index.html b/pkg/client-sdk/test/wasm/web/index.html new file mode 100644 index 000000000..b4237ec8f --- /dev/null +++ b/pkg/client-sdk/test/wasm/web/index.html @@ -0,0 +1,20 @@ + + + + + Ark SDK WASM Example + + + + +

Ark SDK WASM Test

+ + \ No newline at end of file