From 02a78bb0b5efabc6a1cd49f71c9cf79f05e6ee3d Mon Sep 17 00:00:00 2001 From: Javed Khan Date: Mon, 18 Mar 2024 07:56:08 -0700 Subject: [PATCH] da: add jsonrpc proxy (#54) * da: grpc -> jsonrpc * da: rm proxy server auth * da: nit typo * da: proxy-grpc; proxy-jsonrpc * da: go mod tidy * da: proxy switch backend with uri * da: ctx; docs * da: pkgs - proxy/grpc proxy/jsonrpc * da: use jsonrpc logger --- go.mod | 10 +++ go.sum | 99 +++++++++++++++++++++- proxy/client.go | 150 ++++++--------------------------- proxy/grpc/client.go | 137 ++++++++++++++++++++++++++++++ proxy/{ => grpc}/proxy_test.go | 4 +- proxy/{ => grpc}/server.go | 2 +- proxy/{ => grpc}/util.go | 2 +- proxy/jsonrpc/client.go | 122 +++++++++++++++++++++++++++ proxy/jsonrpc/proxy_test.go | 39 +++++++++ proxy/jsonrpc/server.go | 85 +++++++++++++++++++ 10 files changed, 522 insertions(+), 128 deletions(-) create mode 100644 proxy/grpc/client.go rename proxy/{ => grpc}/proxy_test.go (90%) rename proxy/{ => grpc}/server.go (99%) rename proxy/{ => grpc}/util.go (98%) create mode 100644 proxy/jsonrpc/client.go create mode 100644 proxy/jsonrpc/proxy_test.go create mode 100644 proxy/jsonrpc/server.go diff --git a/go.mod b/go.mod index 372212d..8732b7e 100644 --- a/go.mod +++ b/go.mod @@ -3,18 +3,28 @@ module github.com/rollkit/go-da go 1.21.1 require ( + github.com/filecoin-project/go-jsonrpc v0.3.1 github.com/gogo/protobuf v1.3.2 + github.com/ipfs/go-log/v2 v2.0.8 github.com/stretchr/testify v1.9.0 google.golang.org/grpc v1.60.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/gorilla/websocket v1.4.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + go.opencensus.io v0.22.3 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.19.1 // indirect golang.org/x/net v0.16.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 3b468ed..924fa61 100644 --- a/go.sum +++ b/go.sum @@ -1,61 +1,158 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/filecoin-project/go-jsonrpc v0.3.1 h1:qwvAUc5VwAkooquKJmfz9R2+F8znhiqcNHYjEp/NM10= +github.com/filecoin-project/go-jsonrpc v0.3.1/go.mod h1:jBSvPTl8V1N7gSTuCR4bis8wnQnIjHbRPpROol6iQKM= 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= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/ipfs/go-log/v2 v2.0.8 h1:3b3YNopMHlj4AvyhWAx0pDxqSQWYi4/WuWO7yRV6/Qg= +github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= 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/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 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/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +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= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/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= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/proxy/client.go b/proxy/client.go index 1f9e967..52df95b 100644 --- a/proxy/client.go +++ b/proxy/client.go @@ -2,136 +2,40 @@ package proxy import ( "context" + "fmt" + "net/url" "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" "github.com/rollkit/go-da" - pbda "github.com/rollkit/go-da/types/pb/da" + proxygrpc "github.com/rollkit/go-da/proxy/grpc" + proxyjsonrpc "github.com/rollkit/go-da/proxy/jsonrpc" ) -// Client is a gRPC proxy client for DA interface. -type Client struct { - conn *grpc.ClientConn - - client pbda.DAServiceClient -} - -// NewClient returns new Client instance. -func NewClient() *Client { - return &Client{} -} - -// Start connects Client to target, with given options. -func (c *Client) Start(target string, opts ...grpc.DialOption) (err error) { - c.conn, err = grpc.Dial(target, opts...) - if err != nil { - return err - } - c.client = pbda.NewDAServiceClient(c.conn) - - return nil -} - -// Stop gently closes Client connection. -func (c *Client) Stop() error { - return c.conn.Close() -} - -// MaxBlobSize returns the DA MaxBlobSize -func (c *Client) MaxBlobSize(ctx context.Context) (uint64, error) { - req := &pbda.MaxBlobSizeRequest{} - resp, err := c.client.MaxBlobSize(ctx, req) - if err != nil { - return 0, err - } - return resp.MaxBlobSize, nil -} - -// Get returns Blob for each given ID, or an error. -func (c *Client) Get(ctx context.Context, ids []da.ID, namespace da.Namespace) ([]da.Blob, error) { - req := &pbda.GetRequest{ - Ids: make([]*pbda.ID, len(ids)), - Namespace: &pbda.Namespace{Value: namespace}, - } - for i := range ids { - req.Ids[i] = &pbda.ID{Value: ids[i]} - } - resp, err := c.client.Get(ctx, req) +// NewClient returns a DA backend based on the uri +// and auth token. Supported schemes: grpc, http, https +func NewClient(uri, token string) (da.DA, error) { + addr, err := url.Parse(uri) if err != nil { return nil, err } - - return blobsPB2DA(resp.Blobs), nil -} - -// GetIDs returns IDs of all Blobs located in DA at given height. -func (c *Client) GetIDs(ctx context.Context, height uint64, namespace da.Namespace) ([]da.ID, error) { - req := &pbda.GetIDsRequest{Height: height, Namespace: &pbda.Namespace{Value: namespace}} - resp, err := c.client.GetIDs(ctx, req) - if err != nil { - return nil, err - } - - return idsPB2DA(resp.Ids), nil -} - -// GetProofs returns inclusion Proofs for all Blobs located in DA at given height. -func (c *Client) GetProofs(ctx context.Context, ids []da.ID, namespace da.Namespace) ([]da.Proof, error) { - req := &pbda.GetProofsRequest{Ids: make([]*pbda.ID, len(ids)), Namespace: &pbda.Namespace{Value: namespace}} - for i := range ids { - req.Ids[i] = &pbda.ID{Value: ids[i]} - } - resp, err := c.client.GetProofs(ctx, req) - if err != nil { - return nil, err - } - - return proofsPB2DA(resp.Proofs), nil -} - -// Commit creates a Commitment for each given Blob. -func (c *Client) Commit(ctx context.Context, blobs []da.Blob, namespace da.Namespace) ([]da.Commitment, error) { - req := &pbda.CommitRequest{ - Blobs: blobsDA2PB(blobs), - Namespace: &pbda.Namespace{Value: namespace}, - } - - resp, err := c.client.Commit(ctx, req) - if err != nil { - return nil, err - } - - return commitsPB2DA(resp.Commitments), nil -} - -// Submit submits the Blobs to Data Availability layer. -func (c *Client) Submit(ctx context.Context, blobs []da.Blob, gasPrice float64, namespace da.Namespace) ([]da.ID, error) { - req := &pbda.SubmitRequest{ - Blobs: blobsDA2PB(blobs), - GasPrice: gasPrice, - Namespace: &pbda.Namespace{Value: namespace}, - } - - resp, err := c.client.Submit(ctx, req) - if err != nil { - return nil, err - } - - ids := make([]da.ID, len(resp.Ids)) - for i := range resp.Ids { - ids[i] = resp.Ids[i].Value - } - - return ids, nil -} - -// Validate validates Commitments against the corresponding Proofs. This should be possible without retrieving the Blobs. -func (c *Client) Validate(ctx context.Context, ids []da.ID, proofs []da.Proof, namespace da.Namespace) ([]bool, error) { - req := &pbda.ValidateRequest{ - Ids: idsDA2PB(ids), - Proofs: proofsDA2PB(proofs), - Namespace: &pbda.Namespace{Value: namespace}, - } - resp, err := c.client.Validate(ctx, req) - return resp.Results, err + var client da.DA + switch addr.Scheme { + case "grpc": + grpcClient := proxygrpc.NewClient() + if err := grpcClient.Start(addr.Host, grpc.WithTransportCredentials(insecure.NewCredentials())); err != nil { + return nil, err + } + client = grpcClient + case "http", "https": + jsonrpcClient, err := proxyjsonrpc.NewClient(context.Background(), uri, token) + if err != nil { + return nil, err + } + client = &jsonrpcClient.DA + default: + return nil, fmt.Errorf("unknown url scheme '%s'", addr.Scheme) + } + return client, nil } diff --git a/proxy/grpc/client.go b/proxy/grpc/client.go new file mode 100644 index 0000000..04d35b0 --- /dev/null +++ b/proxy/grpc/client.go @@ -0,0 +1,137 @@ +package grpc + +import ( + "context" + + "google.golang.org/grpc" + + "github.com/rollkit/go-da" + pbda "github.com/rollkit/go-da/types/pb/da" +) + +// Client is a gRPC proxy client for DA interface. +type Client struct { + conn *grpc.ClientConn + + client pbda.DAServiceClient +} + +// NewClient returns new Client instance. +func NewClient() *Client { + return &Client{} +} + +// Start connects Client to target, with given options. +func (c *Client) Start(target string, opts ...grpc.DialOption) (err error) { + c.conn, err = grpc.Dial(target, opts...) + if err != nil { + return err + } + c.client = pbda.NewDAServiceClient(c.conn) + + return nil +} + +// Stop gently closes Client connection. +func (c *Client) Stop() error { + return c.conn.Close() +} + +// MaxBlobSize returns the DA MaxBlobSize +func (c *Client) MaxBlobSize(ctx context.Context) (uint64, error) { + req := &pbda.MaxBlobSizeRequest{} + resp, err := c.client.MaxBlobSize(ctx, req) + if err != nil { + return 0, err + } + return resp.MaxBlobSize, nil +} + +// Get returns Blob for each given ID, or an error. +func (c *Client) Get(ctx context.Context, ids []da.ID, namespace da.Namespace) ([]da.Blob, error) { + req := &pbda.GetRequest{ + Ids: make([]*pbda.ID, len(ids)), + Namespace: &pbda.Namespace{Value: namespace}, + } + for i := range ids { + req.Ids[i] = &pbda.ID{Value: ids[i]} + } + resp, err := c.client.Get(ctx, req) + if err != nil { + return nil, err + } + + return blobsPB2DA(resp.Blobs), nil +} + +// GetIDs returns IDs of all Blobs located in DA at given height. +func (c *Client) GetIDs(ctx context.Context, height uint64, namespace da.Namespace) ([]da.ID, error) { + req := &pbda.GetIDsRequest{Height: height, Namespace: &pbda.Namespace{Value: namespace}} + resp, err := c.client.GetIDs(ctx, req) + if err != nil { + return nil, err + } + + return idsPB2DA(resp.Ids), nil +} + +// GetProofs returns inclusion Proofs for all Blobs located in DA at given height. +func (c *Client) GetProofs(ctx context.Context, ids []da.ID, namespace da.Namespace) ([]da.Proof, error) { + req := &pbda.GetProofsRequest{Ids: make([]*pbda.ID, len(ids)), Namespace: &pbda.Namespace{Value: namespace}} + for i := range ids { + req.Ids[i] = &pbda.ID{Value: ids[i]} + } + resp, err := c.client.GetProofs(ctx, req) + if err != nil { + return nil, err + } + + return proofsPB2DA(resp.Proofs), nil +} + +// Commit creates a Commitment for each given Blob. +func (c *Client) Commit(ctx context.Context, blobs []da.Blob, namespace da.Namespace) ([]da.Commitment, error) { + req := &pbda.CommitRequest{ + Blobs: blobsDA2PB(blobs), + Namespace: &pbda.Namespace{Value: namespace}, + } + + resp, err := c.client.Commit(ctx, req) + if err != nil { + return nil, err + } + + return commitsPB2DA(resp.Commitments), nil +} + +// Submit submits the Blobs to Data Availability layer. +func (c *Client) Submit(ctx context.Context, blobs []da.Blob, gasPrice float64, namespace da.Namespace) ([]da.ID, error) { + req := &pbda.SubmitRequest{ + Blobs: blobsDA2PB(blobs), + GasPrice: gasPrice, + Namespace: &pbda.Namespace{Value: namespace}, + } + + resp, err := c.client.Submit(ctx, req) + if err != nil { + return nil, err + } + + ids := make([]da.ID, len(resp.Ids)) + for i := range resp.Ids { + ids[i] = resp.Ids[i].Value + } + + return ids, nil +} + +// Validate validates Commitments against the corresponding Proofs. This should be possible without retrieving the Blobs. +func (c *Client) Validate(ctx context.Context, ids []da.ID, proofs []da.Proof, namespace da.Namespace) ([]bool, error) { + req := &pbda.ValidateRequest{ + Ids: idsDA2PB(ids), + Proofs: proofsDA2PB(proofs), + Namespace: &pbda.Namespace{Value: namespace}, + } + resp, err := c.client.Validate(ctx, req) + return resp.Results, err +} diff --git a/proxy/proxy_test.go b/proxy/grpc/proxy_test.go similarity index 90% rename from proxy/proxy_test.go rename to proxy/grpc/proxy_test.go index 0322678..c32ea6d 100644 --- a/proxy/proxy_test.go +++ b/proxy/grpc/proxy_test.go @@ -1,4 +1,4 @@ -package proxy_test +package grpc_test import ( "net" @@ -8,7 +8,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "github.com/rollkit/go-da/proxy" + proxy "github.com/rollkit/go-da/proxy/grpc" "github.com/rollkit/go-da/test" ) diff --git a/proxy/server.go b/proxy/grpc/server.go similarity index 99% rename from proxy/server.go rename to proxy/grpc/server.go index 048bf40..5d5c2fb 100644 --- a/proxy/server.go +++ b/proxy/grpc/server.go @@ -1,4 +1,4 @@ -package proxy +package grpc import ( "context" diff --git a/proxy/util.go b/proxy/grpc/util.go similarity index 98% rename from proxy/util.go rename to proxy/grpc/util.go index 6ee79f9..4b66c98 100644 --- a/proxy/util.go +++ b/proxy/grpc/util.go @@ -1,4 +1,4 @@ -package proxy +package grpc import ( "github.com/rollkit/go-da" diff --git a/proxy/jsonrpc/client.go b/proxy/jsonrpc/client.go new file mode 100644 index 0000000..965f29c --- /dev/null +++ b/proxy/jsonrpc/client.go @@ -0,0 +1,122 @@ +package jsonrpc + +import ( + "context" + "fmt" + "net/http" + + "github.com/filecoin-project/go-jsonrpc" + + "github.com/rollkit/go-da" +) + +// Module wraps the DA interface +// +//go:generate mockgen -destination=mocks/api.go -package=mocks . Module +type Module interface { + da.DA +} + +// API defines the jsonrpc service module API +type API struct { + Internal struct { + MaxBlobSize func(ctx context.Context) (uint64, error) `perm:"read"` + Get func(ctx context.Context, ids []da.ID, ns da.Namespace) ([]da.Blob, error) `perm:"read"` + GetIDs func(ctx context.Context, height uint64, ns da.Namespace) ([]da.ID, error) `perm:"read"` + GetProofs func(ctx context.Context, ids []da.ID, ns da.Namespace) ([]da.Proof, error) `perm:"read"` + Commit func(ctx context.Context, blobs []da.Blob, ns da.Namespace) ([]da.Commitment, error) `perm:"read"` + Validate func(context.Context, []da.ID, []da.Proof, da.Namespace) ([]bool, error) `perm:"read"` + Submit func(context.Context, []da.Blob, float64, da.Namespace) ([]da.ID, error) `perm:"write"` + } +} + +// MaxBlobSize returns the max blob size +func (api *API) MaxBlobSize(ctx context.Context) (uint64, error) { + return api.Internal.MaxBlobSize(ctx) +} + +// Get returns Blob for each given ID, or an error. +func (api *API) Get(ctx context.Context, ids []da.ID, ns da.Namespace) ([]da.Blob, error) { + return api.Internal.Get(ctx, ids, ns) +} + +// GetIDs returns IDs of all Blobs located in DA at given height. +func (api *API) GetIDs(ctx context.Context, height uint64, ns da.Namespace) ([]da.ID, error) { + return api.Internal.GetIDs(ctx, height, ns) +} + +// GetProofs returns inclusion Proofs for Blobs specified by their IDs. +func (api *API) GetProofs(ctx context.Context, ids []da.ID, ns da.Namespace) ([]da.Proof, error) { + return api.Internal.GetProofs(ctx, ids, ns) +} + +// Commit creates a Commitment for each given Blob. +func (api *API) Commit(ctx context.Context, blobs []da.Blob, ns da.Namespace) ([]da.Commitment, error) { + return api.Internal.Commit(ctx, blobs, ns) +} + +// Validate validates Commitments against the corresponding Proofs. This should be possible without retrieving the Blobs. +func (api *API) Validate(ctx context.Context, ids []da.ID, proofs []da.Proof, ns da.Namespace) ([]bool, error) { + return api.Internal.Validate(ctx, ids, proofs, ns) +} + +// Submit submits the Blobs to Data Availability layer. +func (api *API) Submit(ctx context.Context, blobs []da.Blob, gasPrice float64, ns da.Namespace) ([]da.ID, error) { + return api.Internal.Submit(ctx, blobs, gasPrice, ns) +} + +// Client is the jsonrpc client +type Client struct { + DA API + closer multiClientCloser +} + +// multiClientCloser is a wrapper struct to close clients across multiple namespaces. +type multiClientCloser struct { + closers []jsonrpc.ClientCloser +} + +// register adds a new closer to the multiClientCloser +func (m *multiClientCloser) register(closer jsonrpc.ClientCloser) { + m.closers = append(m.closers, closer) +} + +// closeAll closes all saved clients. +func (m *multiClientCloser) closeAll() { + for _, closer := range m.closers { + closer() + } +} + +// Close closes the connections to all namespaces registered on the staticClient. +func (c *Client) Close() { + c.closer.closeAll() +} + +// NewClient creates a new Client with one connection per namespace with the +// given token as the authorization token. +func NewClient(ctx context.Context, addr string, token string) (*Client, error) { + authHeader := http.Header{"Authorization": []string{fmt.Sprintf("Bearer %s", token)}} + return newClient(ctx, addr, authHeader) +} + +func newClient(ctx context.Context, addr string, authHeader http.Header) (*Client, error) { + var multiCloser multiClientCloser + var client Client + for name, module := range moduleMap(&client) { + closer, err := jsonrpc.NewClient(ctx, addr, name, module, authHeader) + if err != nil { + return nil, err + } + multiCloser.register(closer) + } + + return &client, nil +} + +func moduleMap(client *Client) map[string]interface{} { + // TODO: this duplication of strings many times across the codebase can be avoided with issue #1176 + return map[string]interface{}{ + "da": &client.DA.Internal, + } +} diff --git a/proxy/jsonrpc/proxy_test.go b/proxy/jsonrpc/proxy_test.go new file mode 100644 index 0000000..3831eca --- /dev/null +++ b/proxy/jsonrpc/proxy_test.go @@ -0,0 +1,39 @@ +package jsonrpc_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + proxy "github.com/rollkit/go-da/proxy/jsonrpc" + "github.com/rollkit/go-da/test" +) + +const ( + // ServerHost is the listen host for the test JSONRPC server + ServerHost = "localhost" + // ServerPort is the listen port for the test JSONRPC server + ServerPort = "3450" + // ClientURL is the url to dial for the test JSONRPC client + ClientURL = "http://localhost:3450" +) + +// TestProxy runs the go-da DA test suite against the JSONRPC service +// NOTE: This test requires a test JSONRPC service to run on the port +// 3450 which is chosen to be sufficiently distinct from the default port +func TestProxy(t *testing.T) { + dummy := test.NewDummyDA() + server := proxy.NewServer(ServerHost, ServerPort, dummy) + err := server.Start(context.Background()) + require.NoError(t, err) + defer func() { + if err := server.Stop(context.Background()); err != nil { + require.NoError(t, err) + } + }() + + client, err := proxy.NewClient(context.Background(), ClientURL, "") + require.NoError(t, err) + test.RunDATestSuite(t, &client.DA) +} diff --git a/proxy/jsonrpc/server.go b/proxy/jsonrpc/server.go new file mode 100644 index 0000000..92b9864 --- /dev/null +++ b/proxy/jsonrpc/server.go @@ -0,0 +1,85 @@ +package jsonrpc + +import ( + "context" + "net" + "net/http" + "sync/atomic" + "time" + + "github.com/filecoin-project/go-jsonrpc" + logging "github.com/ipfs/go-log/v2" + + "github.com/rollkit/go-da" +) + +var log = logging.Logger("jsonrpc") + +// Server is a jsonrpc service that can serve the DA interface +type Server struct { + srv *http.Server + rpc *jsonrpc.RPCServer + listener net.Listener + + started atomic.Bool +} + +// RegisterService registers a service onto the RPC server. All methods on the service will then be +// exposed over the RPC. +func (s *Server) RegisterService(namespace string, service interface{}, out interface{}) { + s.rpc.Register(namespace, service) +} + +// NewServer accepts the host address port and the DA implementation to serve as a jsonrpc service +func NewServer(address, port string, DA da.DA) *Server { + rpc := jsonrpc.NewServer() + srv := &Server{ + rpc: rpc, + srv: &http.Server{ + Addr: address + ":" + port, + // the amount of time allowed to read request headers. set to the default 2 seconds + ReadHeaderTimeout: 2 * time.Second, + }, + } + srv.srv.Handler = http.HandlerFunc(rpc.ServeHTTP) + srv.RegisterService("da", DA, &API{}) + return srv +} + +// Start starts the RPC Server. +// This function can be called multiple times concurrently +// Once started, subsequent calls are a no-op +func (s *Server) Start(context.Context) error { + couldStart := s.started.CompareAndSwap(false, true) + if !couldStart { + log.Warn("cannot start server: already started") + return nil + } + listener, err := net.Listen("tcp", s.srv.Addr) + if err != nil { + return err + } + s.listener = listener + log.Infow("server started", "listening on", s.srv.Addr) + //nolint:errcheck + go s.srv.Serve(listener) + return nil +} + +// Stop stops the RPC Server. +// This function can be called multiple times concurrently +// Once stopped, subsequent calls are a no-op +func (s *Server) Stop(ctx context.Context) error { + couldStop := s.started.CompareAndSwap(true, false) + if !couldStop { + log.Warn("cannot stop server: already stopped") + return nil + } + err := s.srv.Shutdown(ctx) + if err != nil { + return err + } + s.listener = nil + log.Info("server stopped") + return nil +}