From 2551affae0f42834f368fcfa67391064add96491 Mon Sep 17 00:00:00 2001 From: bahadylbekov <33404905+bahadylbekov@users.noreply.github.com> Date: Fri, 13 Nov 2020 17:04:10 +0300 Subject: [PATCH] add: solana rpc, solana program subscription, miner beacon entries usage, fixed DioneStaking smart contract --- consensus/miner.go | 10 ++- docs/task-mining.md | 2 + docs/task.md | 2 +- eth-contracts/contracts/DioneStaking.sol | 12 +--- go.mod | 4 +- go.sum | 20 ++++++ models/filecoin-message.go | 27 +++++++ rpc/ethereum.go | 36 ---------- rpc/filecoin.go | 16 ----- rpc/rpc.go | 16 +++++ solana/client.go | 89 ++++++++++++++++++++++++ solana/types/error.go | 6 ++ solana/types/response.go | 8 +++ solana/types/subscription.go | 34 +++++++++ 14 files changed, 217 insertions(+), 65 deletions(-) create mode 100644 docs/task-mining.md create mode 100644 models/filecoin-message.go delete mode 100644 rpc/ethereum.go create mode 100644 solana/client.go create mode 100644 solana/types/error.go create mode 100644 solana/types/response.go create mode 100644 solana/types/subscription.go diff --git a/consensus/miner.go b/consensus/miner.go index 0c91504..025c550 100644 --- a/consensus/miner.go +++ b/consensus/miner.go @@ -64,13 +64,19 @@ func (m *Miner) MineTask(ctx context.Context, base *MiningBase, mb *MinerBase) ( logrus.Debug("attempting to mine the task at epoch: ", round) prevEntry := mb.PrevBeaconEntry + bvals := mb.BeaconEntries - ticket, err := m.computeTicket(ctx, &prevEntry, base, mb) + rbase := prevEntry + if len(bvals) > 0 { + rbase = bvals[len(bvals)-1] + } + + ticket, err := m.computeTicket(ctx, &rbase, base, mb) if err != nil { return nil, xerrors.Errorf("scratching ticket failed: %w", err) } - winner, err := IsRoundWinner(ctx, round, m.address, prevEntry, mb, m.api) + winner, err := IsRoundWinner(ctx, round, m.address, rbase, mb, m.api) if err != nil { return nil, xerrors.Errorf("failed to check if we win next round: %w", err) } diff --git a/docs/task-mining.md b/docs/task-mining.md new file mode 100644 index 0000000..94b0baf --- /dev/null +++ b/docs/task-mining.md @@ -0,0 +1,2 @@ +# Mining in Dione network + diff --git a/docs/task.md b/docs/task.md index 1cbbdd0..5fa9765 100644 --- a/docs/task.md +++ b/docs/task.md @@ -2,7 +2,7 @@ Task is a computational unit in Dione oracle network. Miners computes the tasks by getting requests from Dione smart contracts on Ethereum chain and making cross-chain operations. -Every task has it's own epoch, miner address who computed the task information corresponding the Dione mining operations, payload that represents the state from another blockchain network, it's own signature etc. (Task types and origin types would be added shortly) +Every task has it's own epoch, miner address who computed the task, information corresponding the Dione mining operations, payload that represents the state from another blockchain network, it's own signature etc. (Task types and origin types would be added shortly) ``` type DioneTask struct { diff --git a/eth-contracts/contracts/DioneStaking.sol b/eth-contracts/contracts/DioneStaking.sol index 1325b32..8b30506 100644 --- a/eth-contracts/contracts/DioneStaking.sol +++ b/eth-contracts/contracts/DioneStaking.sol @@ -106,15 +106,9 @@ contract DioneStaking is Ownable, ReentrancyGuard { return _totalStake; } -// disabled for security reason -// function minerStake(address _minerAddr) external view returns (uint256) { -// MinerInfo storage miner = minerInfo[_minerAddr]; -// return miner.amount; -// } - - function minerStake() external view returns (uint256) { - MinerInfo storage miner = minerInfo[msg.sender]; - return miner.amount; + function minerStake(address _minerAddr) external view returns (uint256) { + MinerInfo storage miner = minerInfo[_minerAddr]; + return miner.amount; } // Update miner reward in DIONE tokens, only can be executed by owner of the contract diff --git a/go.mod b/go.mod index 142b974..e95c7ba 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/cespare/cp v1.1.1 // indirect github.com/deckarep/golang-set v1.7.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect + github.com/dgrr/fastws v1.0.0 github.com/drand/drand v1.2.1 github.com/drand/kyber v1.1.5 github.com/elastic/gosigar v0.10.5 // indirect @@ -46,6 +47,7 @@ require ( github.com/raulk/clock v1.1.0 github.com/rjeczalik/notify v0.9.2 // indirect github.com/rs/cors v1.7.0 // indirect + github.com/shengdoushi/base58 v1.0.0 github.com/sirupsen/logrus v1.7.0 github.com/smartystreets/assertions v1.0.1 // indirect github.com/spf13/viper v1.7.1 @@ -54,12 +56,12 @@ require ( github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect github.com/stretchr/testify v1.6.1 github.com/tyler-smith/go-bip39 v1.0.2 // indirect + github.com/valyala/fasthttp v1.17.0 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a // indirect github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163 github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 // indirect github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect - golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 google.golang.org/protobuf v1.25.0 // indirect diff --git a/go.sum b/go.sum index 40ff551..0e81fce 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2c github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4= +github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -151,6 +153,8 @@ github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdo github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrr/fastws v1.0.0 h1:FOSkzHJncrhAVUYtJkgT/mJ40wNom9RHpyWd5rPTFDI= +github.com/dgrr/fastws v1.0.0/go.mod h1:myCByhzpoGTt2o2yOaY3hkYf1htJFrdUURbaGsqfxGc= github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -469,6 +473,9 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 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/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg= +github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -934,6 +941,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/sercand/kuberesolver v2.1.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ= github.com/sercand/kuberesolver v2.4.0+incompatible h1:WE2OlRf6wjLxHwNkkFLQGaZcVLEXjMjBPjjEU5vksH8= github.com/sercand/kuberesolver v2.4.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ= +github.com/shengdoushi/base58 v1.0.0 h1:tGe4o6TmdXFJWoI31VoSWvuaKxf0Px3gqa3sUWhAxBs= +github.com/shengdoushi/base58 v1.0.0/go.mod h1:m5uIILfzcKMw6238iWAhP4l3s5+uXyF3+bJKUNhAL9I= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8= @@ -1018,6 +1027,12 @@ github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.12.0/go.mod h1:229t1eWu9UXTPmoUkbpN/fctKPBY4IJoFXQnxHGXy6E= +github.com/valyala/fasthttp v1.17.0 h1:P8/koH4aSnJ4xbd0cUUFEGQs3jQqIxoDDyRQrUiAkqg= +github.com/valyala/fasthttp v1.17.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= @@ -1181,6 +1196,7 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= @@ -1188,6 +1204,7 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1260,12 +1277,15 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c h1:38q6VNPWR010vN82/SB121GujZNIfAUb4YttE2rhGuc= golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201027140754-0fcbb8f4928c h1:2+jF2APAgFgXJnYOQGDGGiRvvEo6OhqZGQf46n9xgEw= golang.org/x/sys v0.0.0-20201027140754-0fcbb8f4928c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/models/filecoin-message.go b/models/filecoin-message.go new file mode 100644 index 0000000..ae07dcc --- /dev/null +++ b/models/filecoin-message.go @@ -0,0 +1,27 @@ +package models + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" +) + +type FilecoinMsg struct { + Version uint64 + + To address.Address + From address.Address + + Nonce uint64 + + Value abi.TokenAmount + + GasLimit int64 + GasFeeCap abi.TokenAmount + GasPremium abi.TokenAmount + + Method abi.MethodNum + Params []byte +} + +type FilMsgSignature *crypto.Signature diff --git a/rpc/ethereum.go b/rpc/ethereum.go deleted file mode 100644 index 92a2c10..0000000 --- a/rpc/ethereum.go +++ /dev/null @@ -1,36 +0,0 @@ -package rpc - -import ( - "bytes" - "fmt" - "net/http" -) - -type infuraClient struct { - url string - apiKey string - network string -} - -// NewInfuraClient returns a new infuraClient. -func NewInfuraClient(apiKey string, network string) Client { - return &infuraClient{ - url: fmt.Sprintf("https://%s.infura.io/v3", network), - apiKey: apiKey, - network: network, - } -} - -// HandleRequest implements the `Client` interface. -func (infura *infuraClient) HandleRequest(r *http.Request, data []byte) (*http.Response, error) { - apiKey := infura.apiKey - if apiKey == "" { - return nil, fmt.Errorf("Can't find any infura API keys") - } - client := http.Client{} - req, err := http.NewRequest("POST", fmt.Sprintf("%s/%s", infura.url, apiKey), bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("Failed to construct Infura post request: %v", err) - } - return client.Do(req) -} diff --git a/rpc/filecoin.go b/rpc/filecoin.go index a477559..76513bf 100644 --- a/rpc/filecoin.go +++ b/rpc/filecoin.go @@ -13,22 +13,6 @@ type LotusClient struct { jwt string } -type RequestBody struct { - Jsonrpc string - Method string - Params []string - ID int -} - -func NewRequestBody(method string) *RequestBody { - return &RequestBody{ - Jsonrpc: "2.0", - Method: method, - Params: []string{}, - ID: 0, - } -} - // NewClient returns a new client. func NewLotusClient(host string, token string) *LotusClient { return &LotusClient{ diff --git a/rpc/rpc.go b/rpc/rpc.go index 2683410..ae4e5f2 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -2,6 +2,22 @@ package rpc import "net/http" +type RequestBody struct { + Jsonrpc string `json:"jsonrpc"` + Method string `json:"method"` + Params []string `json:"params"` + ID int `json:"id"` +} + +func NewRequestBody(method string) *RequestBody { + return &RequestBody{ + Jsonrpc: "2.0", + Method: method, + Params: []string{}, + ID: 0, + } +} + type Client interface { HandleRequest(r *http.Request, data []byte) (*http.Response, error) } diff --git a/solana/client.go b/solana/client.go new file mode 100644 index 0000000..8a958e5 --- /dev/null +++ b/solana/client.go @@ -0,0 +1,89 @@ +package solana + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/Secured-Finance/dione/rpc" + types "github.com/Secured-Finance/dione/solana/types" + ws "github.com/dgrr/fastws" + "github.com/shengdoushi/base58" + "github.com/sirupsen/logrus" + "github.com/valyala/fasthttp" +) + +var solanaAlphabet = base58.BitcoinAlphabet + +type SolanaClient struct { + url string + ws string +} + +// NewSolanaClient creates a new solana client structure. +func NewSolanaClient() *SolanaClient { + return &SolanaClient{ + url: "http://devnet.solana.com:8899/", + ws: "ws://devnet.solana.com:8900/", + } +} + +func (c *SolanaClient) GetTransaction(txHash string) (*fasthttp.Response, error) { + req := fasthttp.AcquireRequest() + req.SetRequestURI(c.url) + req.Header.SetMethod("POST") + req.Header.SetContentType("application/json") + requestBody := rpc.NewRequestBody("getConfirmedTransaction") + requestBody.Params = append(requestBody.Params, txHash, "base58") + body, err := json.Marshal(requestBody) + if err != nil { + return nil, fmt.Errorf("Failed to marshal request body %v", err) + } + req.AppendBody(body) + resp := fasthttp.AcquireResponse() + client := &fasthttp.Client{} + if err = client.Do(req, resp); err != nil { + logrus.Warn("Failed to construct solana node rpc request", err) + return nil, err + } + bodyBytes := resp.Body() + logrus.Info(string(bodyBytes)) + return resp, nil +} + +func (c *SolanaClient) subsctibeOnProgram(programID string) { + conn, err := ws.Dial(c.ws) + if err != nil { + log.Fatalln("Can't establish connection with Solana websocket: ", err) + } + defer conn.Close() + + requestBody := rpc.NewRequestBody("programSubscribe") + requestBody.Params = append(requestBody.Params, programID) + + body, err := json.Marshal(requestBody) + if err != nil { + logrus.Errorf("Couldn't unmarshal parameters to request body %v", err) + } + + subscriptionID, err := conn.Write(body) + if err != nil { + logrus.Errorf("Couldn't send a websocket request to Solana node %v", err) + } + logrus.Info("Websocket established with ProgramID:", programID) + logrus.Info("Subscription ID to drop websocket connection:", subscriptionID) + + var msg []byte + var parsedSub *types.Subscription + for { + _, msg, err = conn.ReadMessage(msg[:0]) + if err != nil { + break + } + json.Unmarshal(msg, &parsedSub) + logrus.Info("Subscription: ", parsedSub) + // TODO: 1) Unmarshal base58 data to program structure in order to read data + // 2) Save data from oracle event in redis cache + // 3) Start mining of Solana oracle event + } +} diff --git a/solana/types/error.go b/solana/types/error.go new file mode 100644 index 0000000..f513ed8 --- /dev/null +++ b/solana/types/error.go @@ -0,0 +1,6 @@ +package types + +type Error struct { + Code int64 `json:"code"` + Message string `json:"message"` +} diff --git a/solana/types/response.go b/solana/types/response.go new file mode 100644 index 0000000..849f8ab --- /dev/null +++ b/solana/types/response.go @@ -0,0 +1,8 @@ +package types + +type SolanaResponse struct { + Jsonrpc string `json:"jsonrpc"` + Result []byte `json:"result"` + Error Error `json:"error"` + ID int64 `json:"id"` +} diff --git a/solana/types/subscription.go b/solana/types/subscription.go new file mode 100644 index 0000000..c2f10d6 --- /dev/null +++ b/solana/types/subscription.go @@ -0,0 +1,34 @@ +package types + +type Subscription struct { + Jsonrpc string `json:"jsonrpc"` + Method string `json:"method"` + Params Params `json:"params"` +} + +type Params struct { + Result Result `json:"result"` + Subscription int `json:"subscription"` +} + +type Result struct { + Context Context `json:"context"` + Value Value `json:"value"` +} + +type Context struct { + Slot int `json:"slot"` +} + +type Value struct { + Pubkey string `json:"pubkey"` + Account Account `json:"account"` +} + +type Account struct { + Data string `json:"data"` + Executable bool `json:"executable"` + Lamports int `json:"lamports"` + Owner string `json:"owner"` + RentEpoch int `json:"rentEpoch"` +}