diff --git a/.gitignore b/.gitignore index 0e823e0..f419e05 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ docker/*/*chain_data/* !docker/*/*chain_data/snapshot5392323.json multy-golos + +.idea/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a279645 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +Copyright 2018 Idealnaya rabota LLC (Republic of Belarus) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute (with limitations described below), sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +You shall not distribute in binary form any substantial portion of the Software if it has any modifications (in source code or assets) compared to original distribution from Idealnaya rabota LLC (Republic of Belarus) obtained from the official repository at https://github.com/Multy-io/ or https://github.com/Appscrunch. + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Multy-Back-Golos b/Multy-Back-Golos new file mode 100755 index 0000000..ba6b326 Binary files /dev/null and b/Multy-Back-Golos differ diff --git a/api/api.go b/api/api.go deleted file mode 100644 index 75cc88f..0000000 --- a/api/api.go +++ /dev/null @@ -1,335 +0,0 @@ -package api - -import ( - "encoding/json" - "log" - "time" - - client "github.com/asuleymanov/golos-go" - "github.com/asuleymanov/golos-go/apis/database" - "github.com/asuleymanov/golos-go/types" -) - -// API is a struct for interaction with golos chain -type API struct { - client *client.Client - account string - activeKey string - TrackedAddresses map[string]bool -} - -// NewAPI initializes and validates new api struct -func NewAPI(endpoints []string, net, account, key string) (*API, error) { - cli, err := client.NewClient(endpoints, net) - log.Println("new client") - if err != nil { - return nil, err - } - api := &API{ - client: cli, - account: account, - activeKey: key, - TrackedAddresses: make(map[string]bool), - } - - client.Key_List[account] = client.Keys{ - AKey: key, - } - return api, nil -} - -// Balance is a struct of all available balances -// basically it's a balance subset of database.Account struct -type Balance struct { - Name string `json:"name"` - Balance string `json:"balance"` - SavingsBalance string `json:"savings_balance"` - SbdBalance string `json:"sbd_balance"` - SavingsSbdBalance string `json:"savings_sbd_balance"` - VestingBalance string `json:"vesting_balance"` -} - -// GetBalances gets balances of multiple accounts at once -// using get_accounts rpc call -// accounts is a slice of account names -func (api *API) GetBalances(accounts []string) ([]*Balance, error) { - accs, err := api.client.Database.GetAccounts(accounts) - if err != nil { - return nil, err - } - balances := make([]*Balance, len(accs)) - for i, acc := range accs { - balances[i] = &Balance{ - Name: acc.Name, - Balance: acc.Balance, - SavingsBalance: acc.SavingsBalance, - SbdBalance: acc.SbdBalance, - SavingsSbdBalance: acc.SavingsSbdBalance, - VestingBalance: acc.VestingBalance, - } - } - return balances, nil -} - -// AccountCheck checks if account already exists -// returns true if account exists -func (api *API) AccountCheck(account string) (exists bool, err error) { - accs, err := api.client.Database.GetAccounts([]string{account}) - if err != nil { - return true, err - } - if len(accs) == 0 { - return false, nil - } else { - return true, nil - } -} - -// GetBalance fetches balances of single account -// using GetBalances -func (api *API) GetBalance(account string) (*Balance, error) { - balances, err := api.GetBalances([]string{account}) - if err != nil { - return nil, err - } - return balances[0], nil -} - -// GetConfig gets node config -func (api *API) GetConfig() (*database.Config, error) { - return api.client.Database.GetConfig() -} - -// authorityFromKey contructs golos-go/types Authority struct from public key -// using https://developers.golos.io/golos-v0.17.0/dc/d58/structgolos_1_1protocol_1_1authority.html -// and https://steemit.com/dsteem/@andravasko/how-to-creating-an-account-with-dsteem-0-6-2017928t16287166z -// cause weights are confusing -func authorityFromKey(key string) *types.Authority { - return &types.Authority{ - WeightThreshold: 1, - KeyAuths: types.StringInt64Map{ - key: 1, - }, - AccountAuths: types.StringInt64Map{}, - } -} - -// AccountCreate creates account by constructing -// account_create operation and broadcasting it -// account is account names -// fee is account creation fee if "0.000 GOLOS" format -// owner, active, posting, memo is a public keys -func (api *API) AccountCreate(account, fee, owner, active, posting, memo string) error { - var ops []types.Operation - - // construct operation - op := &types.AccountCreateOperation{ - Fee: fee, - Creator: api.account, - NewAccountName: account, - Owner: authorityFromKey(owner), - Active: authorityFromKey(active), - Posting: authorityFromKey(posting), - MemoKey: memo, - JsonMetadata: "{}", - } - - ops = append(ops, op) - - resp, err := api.client.SendTrx(api.account, ops) - - log.Printf("Response: %s", resp) - - return err -} - -// TrackAddresses adds addresses for tracking -// addresses is a slice of account names -func (api *API) TrackAddresses(addresses []string) error { - for _, addr := range addresses { - api.TrackedAddresses[addr] = true - } - return nil -} - -// GetTrackedAddresses gets currently tracked accounts names -func (api *API) GetTrackedAddresses() ([]string, error) { - accounts := make([]string, 0, len(api.TrackedAddresses)) - for k, _ := range api.TrackedAddresses { - accounts = append(accounts, k) - } - return accounts, nil - -} - -// SendTransaction syncronously broadcasts constructed transaction to a chain -func (api *API) SendTransaction(trx *types.Transaction) (*json.RawMessage, error) { - return api.client.NetworkBroadcast.BroadcastTransactionSynchronousRaw(trx) -} - -// NewBlockLoop checks for new blocks and send them to chans -// start is a number of starting block for iteration -// if start is 0, using head_block_number -func (api *API) NewBlockLoop(blockChan chan<- *NewBlockMessage, balanceChan chan<- *BalancesChangedMessage, done <-chan bool, start uint32) { - blockNum := start - - config, err := api.client.Database.GetConfig() - if err != nil { - log.Printf("get config: %s", err) - return - } - - for { - props, err := api.client.Database.GetDynamicGlobalProperties() - if err != nil { - log.Printf("get global properties: %s", err) - time.Sleep(time.Duration(config.SteemitBlockInterval) * time.Second) - continue - } - if blockNum == 0 { - blockNum = props.HeadBlockNumber - } - // maybe LastIrreversibleBlockNum, cause possible microforks - if props.HeadBlockNumber-blockNum > 0 { - block, err := api.client.Database.GetBlock(blockNum + 1) - if err != nil { - log.Printf("get block: %s", err) - time.Sleep(time.Duration(config.SteemitBlockInterval) * time.Second) - continue - } - msg := &NewBlockMessage{ - Height: block.Number, - Time: block.Timestamp.Unix(), - Transactions: block.Transactions, - } - select { - case <-done: - close(blockChan) - close(balanceChan) - log.Println("end new block loop") - return - case blockChan <- msg: - // process block, now its only balance change check - go api.processBalance(block, balanceChan, done) - } - blockNum++ - } else { - time.Sleep(time.Duration(config.SteemitBlockInterval) * time.Second) - } - } -} - -// getNames gets account names of balance changing operations -// based on https://developers.golos.io/golos-v0.17.0/da/d67/structgolos_1_1protocol_1_1base__operation.html -func getNames(rawOp types.Operation) []string { - switch op := rawOp.Data().(type) { - case *types.VoteOperation: // vote_operation - return []string{op.Voter, op.Author} - case *types.TransferOperation: // transfer_operation - return []string{op.From, op.To} - case *types.TransferToVestingOperation: // transfer_to_vesting_operation - return []string{op.From, op.To} - case *types.WithdrawVestingOperation: // withdraw_vesting_operation - return []string{op.Account} - case *types.LimitOrderCreateOperation: // limit_order_create_operation - return []string{op.Owner} - case *types.LimitOrderCancelOperation: // limit_order_cancel_operation - return []string{op.Owner} - case *types.ConvertOperation: // convert_operation - return []string{op.Owner} - case *types.AccountCreateOperation: // account_create_operation - return []string{op.Creator} - case *types.WitnessUpdateOperation: // witness_update_operation - return []string{op.Owner} - case *types.POWOperation: // pow_operation - return []string{op.WorkerAccount} - case *types.SetWithdrawVestingRouteOperation: // set_withdraw_vesting_route_operation - return []string{op.FromAccount, op.ToAccount} - case *types.LimitOrderCreate2Operation: // limit_order_create2_operation - return []string{op.Qwner} // TODO: fix typo in golos-go - case *types.EscrowTransferOperation: // escrow_transfer_operation - return []string{op.From} - case *types.EscrowReleaseOperation: // escrow_release_operation - return []string{op.From, op.To, op.Agent} - case *types.POW2Operation: // pow2_operation - if op.Input != nil { - return []string{op.Input.WorkerAccount} - } - return []string{} - case *types.TransferToSavingsOperation: // transfer_to_savings_operation - return []string{op.From, op.To} - case *types.TransferFromSavingsOperation: // transfer_from_savings_operation - return []string{op.From, op.To} - case *types.ClaimRewardBalanceOperation: // claim_reward_balance_operation - return []string{op.Account} - case *types.DelegateVestingSharesOperation: // delegate_vesting_shares_operation - return []string{op.Delegatee, op.Delegator} - case *types.AccountCreateWithDelegationOperation: // account_create_with_delegation_operation - return []string{op.Creator, op.NewAccountName} - case *types.FillConvertRequestOperation: // fill_convert_request_operation - return []string{op.Owner} - case *types.AuthorRewardOperation: // author_reward_operation - return []string{op.Author} - case *types.CurationRewardOperation: // curation_reward_operation - return []string{op.CommentAuthor, op.Curator} - case *types.CommentRewardOperation: // comment_reward_operation - return []string{op.Author} - case *types.LiquidityRewardOperation: // liquidity_reward_operation - return []string{op.Owner} - case *types.InterestOperation: // interest_operation - return []string{op.Owner} - case *types.FillVestingWithdrawOperation: // fill_vesting_withdraw_operation - return []string{op.FromAccount, op.ToAccount} - case *types.FillOrderOperation: // fill_order_operation - return []string{op.CurrentOwner, op.OpenOwner} - case *types.FillTransferFromSavingsOperation: // fill_transfer_from_savings_operation - return []string{op.From, op.To} - case *types.ReturnVestingDelegationOperation: // return_vesting_delegation_operation - return []string{op.Account} - case *types.CommentBenefactorRewardOperation: // comment_benefactor_reward_operation - return []string{op.Author, op.Benefactor} - } - return nil -} - -// processBalance finds ops that changes balance that involves tracked addresses -// and pushes updated balances to chanel -func (api *API) processBalance(block *database.Block, balanceChan chan<- *BalancesChangedMessage, done <-chan bool) { - changedBalance := map[string]bool{} - checkAddrs := []string{} - addrs := []string{} - for _, tx := range block.Transactions { - for _, op := range tx.Operations { - addrs = append(addrs, getNames(op)...) - } - } - for _, addr := range addrs { - // if already in checking - if _, ok := changedBalance[addr]; !ok { - // if tracked - if _, ok := api.TrackedAddresses[addr]; ok { - changedBalance[addr] = true - checkAddrs = append(checkAddrs, addr) - } - } - } - if len(checkAddrs) > 0 { - balances, err := api.GetBalances(checkAddrs) - if err != nil { - // BUG: unchecked balances for block on error - log.Printf("get balance: %s", err) - return - } - msg := &BalancesChangedMessage{ - Balances: balances, - } - select { - case <-done: - log.Println("process block done") - return - case balanceChan <- msg: - return - } - } - return -} diff --git a/api/messages.go b/api/messages.go deleted file mode 100644 index f431af7..0000000 --- a/api/messages.go +++ /dev/null @@ -1,74 +0,0 @@ -package api - -import ( - "encoding/json" - - "github.com/asuleymanov/golos-go/types" -) - -// OkErrResponse is a basic completion response with optional error -type OkErrResponse struct { - Ok bool `json:"ok"` - Error string `json:"error,omitempty"` -} - -type AccountCheckRequest struct { - Name string `json:"name"` -} - -type AccountCheckResponse struct { - Exist bool `json:"exist"` - Error string `json:"error"` -} - -type GetBalancesRequest struct { - Accounts []string `json:"accounts"` -} - -type GetBalancesResponse struct { - Balances []*Balance `json:"balances"` - Error string `json:"error"` -} - -type AccountCreateRequest struct { - Account string `json:"account"` - Owner string `json:"owner"` - Active string `json:"active"` - Posting string `json:"posting"` - Memo string `json:"memo"` -} - -type AccountCreateResponse = OkErrResponse - -type BalancesChangedMessage struct { - Balances []*Balance `json:"balances"` -} - -type NewBlockMessage struct { - Height uint32 `json:"height,omitempty"` - // Hash string `json:"hash,omitempty"` - Time int64 `json:"time,omitempty"` - Transactions []*types.Transaction `json:"transactions"` -} - -type TrackAddressesRequest struct { - Adresses []string `json:"adresses,omitempty"` -} - -type TrackAddressesResponse = OkErrResponse - -type GetTrackedAddressesRequest struct { -} - -type GetTrackedAddressesResponse struct { - Accounts []string `json:"accounts"` - Error string `json:"error,omitempty"` -} - -type SendTransactionRequest = types.Transaction - -type SendTransactionResponse struct { - Ok bool `json:"ok"` - Error string `json:"error,omitempty"` - Response *json.RawMessage `json:"response,omitempty"` -} diff --git a/golos/golos.go b/golos/golos.go new file mode 100644 index 0000000..65cf700 --- /dev/null +++ b/golos/golos.go @@ -0,0 +1,99 @@ +/* + * Copyright 2018 Idealnaya rabota LLC + * Licensed under Multy.io license. + * See LICENSE for details + */ + +package golos + +import ( + "log" + + client "github.com/asuleymanov/golos-go" + pb "github.com/Appscrunch/Multy-Back-Golos/proto" + "time" +) + +// Server is a struct for interaction with golos chain +type Server struct { + client *client.Client + account string + activeKey string + TrackedAddresses map[string]bool + BalanceChangedCh chan *pb.Balance + NewBlockCh chan *pb.Block +} + +// NewServer initializes and validates new api struct +// and runs chain monitoring loop +func NewServer(endpoints []string, net, account, key string) (*Server, error) { + cli, err := client.NewClient(endpoints, net) + log.Println("new client") + if err != nil { + return nil, err + } + s := &Server{ + client: cli, + account: account, + activeKey: key, + TrackedAddresses: make(map[string]bool), + } + + client.Key_List[account] = client.Keys{ + AKey: key, + } + + s.BalanceChangedCh = make(chan *pb.Balance) + s.NewBlockCh = make(chan *pb.Block) + + go s.ProcessLoop(0) + + return s, nil +} + +// NewBlockLoop checks for new blocks and send them to chans +// start is a number of starting block for iteration +// if start is 0, using head_block_number +func (s *Server) ProcessLoop(start uint32) { + blockNum := start + + config, err := s.client.Database.GetConfig() + if err != nil { + log.Printf("get config: %s", err) + return + } + + for { + props, err := s.client.Database.GetDynamicGlobalProperties() + if err != nil { + log.Printf("get global properties: %s", err) + time.Sleep(time.Duration(config.SteemitBlockInterval) * time.Second) + continue + } + if blockNum == 0 { + blockNum = props.HeadBlockNumber + } + // maybe LastIrreversibleBlockNum, cause possible microforks + if props.HeadBlockNumber-blockNum > 0 { + log.Printf("new block: %d", blockNum + 1) + block, err := s.client.Database.GetBlock(blockNum + 1) + if err != nil { + log.Printf("get block: %s", err) + time.Sleep(time.Duration(config.SteemitBlockInterval) * time.Second) + continue + } + msg := makeBlock(block) + select { + case s.NewBlockCh <- &msg: + // process block, now its only balance change check + go s.processBalance(block) + } + blockNum++ + } else { + time.Sleep(time.Duration(config.SteemitBlockInterval) * time.Second) + } + } +} + + + diff --git a/golos/grpc.go b/golos/grpc.go new file mode 100644 index 0000000..edbfbba --- /dev/null +++ b/golos/grpc.go @@ -0,0 +1,184 @@ +/* + * Copyright 2018 Idealnaya rabota LLC + * Licensed under Multy.io license. + * See LICENSE for details + */ + +package golos + +import ( + "context" + + "github.com/asuleymanov/golos-go/types" + + pb "github.com/Appscrunch/Multy-Back-Golos/proto" + "log" + "encoding/json" +) + +// EventGetBlockInfo returns head block info +func (s *Server) EventGetHeadInfo(ctx context.Context, _ *pb.Empty) (*pb.HeadInfo, error){ + props, err := s.client.Database.GetDynamicGlobalProperties() + if err != nil { + return nil, err + } + resp := &pb.HeadInfo{ + Height:props.HeadBlockNumber, + Id:props.HeadBlockID, + } + return resp, nil +} + +// EventAccountCheck checks if account already exists +// returns true if account exists +func (s *Server) EventAccountCheck(ctx context.Context, request *pb.AccountCheckRequest) (*pb.AccountCheckResponse, error) { + accs, err := s.client.Database.GetAccounts([]string{request.Name}) + if err != nil { + return &pb.AccountCheckResponse{ + Exist:true, + Error: err.Error(), + }, err + } + if len(accs) == 0 { + return &pb.AccountCheckResponse{ + Exist: false, + }, nil + } else { + return &pb.AccountCheckResponse{ + Exist:true, + }, nil + } +} + +// EventAccountCreate creates account by constructing +// account_create operation and broadcasting it +// account is account name +// fee is account creation fee if "0.000 GOLOS" format +// owner, active, posting, memo is a public keys +func (s *Server) EventAccountCreate(ctx context.Context, request *pb.AccountCreateRequest) (*pb.OkErrResponse, error) { + //account, fee, owner, active, posting, memo string + var ops []types.Operation + + // construct operation + op := &types.AccountCreateOperation{ + Fee: request.Fee, + Creator: s.account, + NewAccountName: request.Account, + Owner: authorityFromKey(request.Owner), + Active: authorityFromKey(request.Active), + Posting: authorityFromKey(request.Posting), + MemoKey: request.Memo, + JsonMetadata: "{}", + } + + ops = append(ops, op) + + resp, err := s.client.SendTrx(s.account, ops) + + if err != nil { + log.Printf("AccountCreate error: resp: %s, req: %s", resp, request) + } + + return &pb.OkErrResponse{ + Ok: err == nil, + Error: err.Error(), + }, err +} + +// authorityFromKey contructs golos-go/types Authority struct from public key +// using https://developers.golos.io/golos-v0.17.0/dc/d58/structgolos_1_1protocol_1_1authority.html +// and https://steemit.com/dsteem/@andravasko/how-to-creating-an-account-with-dsteem-0-6-2017928t16287166z +// cause weights are confusing +func authorityFromKey(key string) *types.Authority { + return &types.Authority{ + WeightThreshold: 1, + KeyAuths: types.StringInt64Map{ + key: 1, + }, + AccountAuths: types.StringInt64Map{}, + } +} + + +// GetBalances gets balances of multiple accounts at once +// using get_accounts rpc call +func (s *Server) EventGetBalances(ctx context.Context, request *pb.Accounts) (*pb.GetBalancesResponse, error) { + accs, err := s.client.Database.GetAccounts(request.Names) + if err != nil { + return nil, err + } + balances := make([]*pb.Balance, len(accs)) + for i, acc := range accs { + balances[i] = &pb.Balance{ + Name: acc.Name, + Balance: acc.Balance, + SavingsBalance: acc.SavingsBalance, + SbdBalance: acc.SbdBalance, + SavingsSbdBalance: acc.SavingsSbdBalance, + VestingBalance: acc.VestingBalance, + } + } + return &pb.GetBalancesResponse{ + Balances: balances, + }, nil +} + +// TrackAddresses adds addresses for tracking +func (s *Server) EventTrackAddresses(ctx context.Context, request *pb.Accounts) (*pb.OkErrResponse, error) { + for _, addr := range request.Names { + s.TrackedAddresses[addr] = true + } + return &pb.OkErrResponse{ + Ok: true, + }, nil +} + +// GetTrackedAddresses gets currently tracked accounts names +func (s *Server) EventGetTrackedAddresses(ctx context.Context, _ *pb.Empty) (*pb.Accounts, error) { + accounts := make([]string, 0, len(s.TrackedAddresses)) + for k := range s.TrackedAddresses { + accounts = append(accounts, k) + } + return &pb.Accounts{ + Names:accounts, + }, nil + +} + +// SendTransaction syncronously broadcasts constructed transaction to a chain +func (s *Server) EventSendTransactionJSON(ctx context.Context, trxRaw *pb.TransactionJSON) (*pb.SendTransactionResponse, error) { + trx := types.Transaction{} + err := json.Unmarshal([]byte(trxRaw.Json), &trx) + if err != nil { + return nil, err + } + bResp, err := s.client.NetworkBroadcast.BroadcastTransactionSynchronousRaw(&trx) + return &pb.SendTransactionResponse{ + Error: err.Error(), + Ok: err == nil, + Response: string(*bResp), + }, nil +} + +func (s *Server) BalanceChanged(_ *pb.Empty, stream pb.NodeCommunications_BalanceChangedServer) error { + for { + select { + case balance := <- s.BalanceChangedCh: + log.Printf("Balance changed %v", balance.String()) + stream.Send(balance) + + } + } + return nil +} + +func (s *Server) NewBlock(_ *pb.Empty, stream pb.NodeCommunications_NewBlockServer) error { + for { + select { + case block := <- s.NewBlockCh: + log.Printf("Balance changed %v", block.String()) + stream.Send(block) + } + } + return nil +} \ No newline at end of file diff --git a/golos/utils.go b/golos/utils.go new file mode 100644 index 0000000..ecc6adb --- /dev/null +++ b/golos/utils.go @@ -0,0 +1,153 @@ +/* + * Copyright 2018 Idealnaya rabota LLC + * Licensed under Multy.io license. + * See LICENSE for details + */ + +package golos + +import ( + "log" + + "github.com/asuleymanov/golos-go/types" + "github.com/asuleymanov/golos-go/apis/database" + + pb "github.com/Appscrunch/Multy-Back-Golos/proto" + "context" +) + +// getNames gets account names of balance changing operations +// based on https://developers.golos.io/golos-v0.17.0/da/d67/structgolos_1_1protocol_1_1base__operation.html +func getNames(rawOp types.Operation) []string { + switch op := rawOp.Data().(type) { + case *types.VoteOperation: // vote_operation + return []string{op.Voter, op.Author} + case *types.TransferOperation: // transfer_operation + return []string{op.From, op.To} + case *types.TransferToVestingOperation: // transfer_to_vesting_operation + return []string{op.From, op.To} + case *types.WithdrawVestingOperation: // withdraw_vesting_operation + return []string{op.Account} + case *types.LimitOrderCreateOperation: // limit_order_create_operation + return []string{op.Owner} + case *types.LimitOrderCancelOperation: // limit_order_cancel_operation + return []string{op.Owner} + case *types.ConvertOperation: // convert_operation + return []string{op.Owner} + case *types.AccountCreateOperation: // account_create_operation + return []string{op.Creator} + case *types.WitnessUpdateOperation: // witness_update_operation + return []string{op.Owner} + case *types.POWOperation: // pow_operation + return []string{op.WorkerAccount} + case *types.SetWithdrawVestingRouteOperation: // set_withdraw_vesting_route_operation + return []string{op.FromAccount, op.ToAccount} + case *types.LimitOrderCreate2Operation: // limit_order_create2_operation + return []string{op.Qwner} // TODO: fix typo in golos-go + case *types.EscrowTransferOperation: // escrow_transfer_operation + return []string{op.From} + case *types.EscrowReleaseOperation: // escrow_release_operation + return []string{op.From, op.To, op.Agent} + case *types.POW2Operation: // pow2_operation + if op.Input != nil { + return []string{op.Input.WorkerAccount} + } + return []string{} + case *types.TransferToSavingsOperation: // transfer_to_savings_operation + return []string{op.From, op.To} + case *types.TransferFromSavingsOperation: // transfer_from_savings_operation + return []string{op.From, op.To} + case *types.ClaimRewardBalanceOperation: // claim_reward_balance_operation + return []string{op.Account} + case *types.DelegateVestingSharesOperation: // delegate_vesting_shares_operation + return []string{op.Delegatee, op.Delegator} + case *types.AccountCreateWithDelegationOperation: // account_create_with_delegation_operation + return []string{op.Creator, op.NewAccountName} + case *types.FillConvertRequestOperation: // fill_convert_request_operation + return []string{op.Owner} + case *types.AuthorRewardOperation: // author_reward_operation + return []string{op.Author} + case *types.CurationRewardOperation: // curation_reward_operation + return []string{op.CommentAuthor, op.Curator} + case *types.CommentRewardOperation: // comment_reward_operation + return []string{op.Author} + case *types.LiquidityRewardOperation: // liquidity_reward_operation + return []string{op.Owner} + case *types.InterestOperation: // interest_operation + return []string{op.Owner} + case *types.FillVestingWithdrawOperation: // fill_vesting_withdraw_operation + return []string{op.FromAccount, op.ToAccount} + case *types.FillOrderOperation: // fill_order_operation + return []string{op.CurrentOwner, op.OpenOwner} + case *types.FillTransferFromSavingsOperation: // fill_transfer_from_savings_operation + return []string{op.From, op.To} + case *types.ReturnVestingDelegationOperation: // return_vesting_delegation_operation + return []string{op.Account} + case *types.CommentBenefactorRewardOperation: // comment_benefactor_reward_operation + return []string{op.Author, op.Benefactor} + } + return nil +} + +// processBalance finds ops that changes balance that involves tracked addresses +// and pushes updated balances to chanel +func (s *Server) processBalance(block *database.Block) { + changedBalance := map[string]bool{} + checkAddrs := []string{} + addrs := []string{} + for _, tx := range block.Transactions { + for _, op := range tx.Operations { + addrs = append(addrs, getNames(op)...) + } + } + for _, addr := range addrs { + // if already in checking + if _, ok := changedBalance[addr]; !ok { + // if tracked + if _, ok := s.TrackedAddresses[addr]; ok { + changedBalance[addr] = true + checkAddrs = append(checkAddrs, addr) + } + } + } + if len(checkAddrs) > 0 { + log.Printf("balances changed %v", checkAddrs) + balances, err := s.EventGetBalances(context.Background(), &pb.Accounts{Names:checkAddrs}) + if err != nil { + // BUG: unchecked balances for block on error + log.Printf("get balance: %s", err) + return + } + for _, b := range balances.Balances { + s.BalanceChangedCh <- b + } + } + return +} + +// makeBlock converts golos-go Block type to protobuf-specified Block type +func makeBlock(block *database.Block) (pb.Block) { + pbBlock := pb.Block{ + Height:block.Number, + Time:block.Timestamp.Unix(), + Transactions: make([]*pb.Block_Transaction, len(block.Transactions)), + } + for i, tx := range block.Transactions { + pbTx := pb.Block_Transaction{ + RefBlockNum: uint32(tx.RefBlockNum), + RefBlockPrefix:uint32(tx.RefBlockPrefix), + Expiration: tx.Expiration.Unix(), + Signatures: tx.Signatures, + } + + ops, err := tx.Operations.MarshalJSON() + if err != nil { + log.Printf("Error marshaling operations: %s", err) + } + + pbTx.Operations = string(ops) + + pbBlock.Transactions[i] = &pbTx + } + return pbBlock +} \ No newline at end of file diff --git a/proto/golos.pb.go b/proto/golos.pb.go new file mode 100644 index 0000000..4ada7b0 --- /dev/null +++ b/proto/golos.pb.go @@ -0,0 +1,928 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: golos.proto + +/* +Package proto is a generated protocol buffer package. + +based on https://github.com/Appscrunch/Multy-back/ + +It is generated from these files: + golos.proto + +It has these top-level messages: + OkErrResponse + AccountCheckRequest + AccountCheckResponse + Accounts + Balance + GetBalancesResponse + AccountCreateRequest + BalancesChangedMessage + GetTrackedAddressesResponse + SendTransactionResponse + Block + HeadInfo + Empty + TransactionJSON +*/ +package proto + +import proto1 "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto1.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto1.ProtoPackageIsVersion2 // please upgrade the proto package + +type OkErrResponse struct { + Ok bool `protobuf:"varint,1,opt,name=ok" json:"ok,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error" json:"error,omitempty"` +} + +func (m *OkErrResponse) Reset() { *m = OkErrResponse{} } +func (m *OkErrResponse) String() string { return proto1.CompactTextString(m) } +func (*OkErrResponse) ProtoMessage() {} +func (*OkErrResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *OkErrResponse) GetOk() bool { + if m != nil { + return m.Ok + } + return false +} + +func (m *OkErrResponse) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +type AccountCheckRequest struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` +} + +func (m *AccountCheckRequest) Reset() { *m = AccountCheckRequest{} } +func (m *AccountCheckRequest) String() string { return proto1.CompactTextString(m) } +func (*AccountCheckRequest) ProtoMessage() {} +func (*AccountCheckRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *AccountCheckRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type AccountCheckResponse struct { + Exist bool `protobuf:"varint,1,opt,name=exist" json:"exist,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error" json:"error,omitempty"` +} + +func (m *AccountCheckResponse) Reset() { *m = AccountCheckResponse{} } +func (m *AccountCheckResponse) String() string { return proto1.CompactTextString(m) } +func (*AccountCheckResponse) ProtoMessage() {} +func (*AccountCheckResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *AccountCheckResponse) GetExist() bool { + if m != nil { + return m.Exist + } + return false +} + +func (m *AccountCheckResponse) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +type Accounts struct { + Names []string `protobuf:"bytes,1,rep,name=names" json:"names,omitempty"` +} + +func (m *Accounts) Reset() { *m = Accounts{} } +func (m *Accounts) String() string { return proto1.CompactTextString(m) } +func (*Accounts) ProtoMessage() {} +func (*Accounts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *Accounts) GetNames() []string { + if m != nil { + return m.Names + } + return nil +} + +type Balance struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Balance string `protobuf:"bytes,2,opt,name=balance" json:"balance,omitempty"` + SavingsBalance string `protobuf:"bytes,3,opt,name=savings_balance,json=savingsBalance" json:"savings_balance,omitempty"` + SbdBalance string `protobuf:"bytes,4,opt,name=sbd_balance,json=sbdBalance" json:"sbd_balance,omitempty"` + SavingsSbdBalance string `protobuf:"bytes,5,opt,name=savings_sbd_balance,json=savingsSbdBalance" json:"savings_sbd_balance,omitempty"` + VestingBalance string `protobuf:"bytes,6,opt,name=vesting_balance,json=vestingBalance" json:"vesting_balance,omitempty"` +} + +func (m *Balance) Reset() { *m = Balance{} } +func (m *Balance) String() string { return proto1.CompactTextString(m) } +func (*Balance) ProtoMessage() {} +func (*Balance) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *Balance) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Balance) GetBalance() string { + if m != nil { + return m.Balance + } + return "" +} + +func (m *Balance) GetSavingsBalance() string { + if m != nil { + return m.SavingsBalance + } + return "" +} + +func (m *Balance) GetSbdBalance() string { + if m != nil { + return m.SbdBalance + } + return "" +} + +func (m *Balance) GetSavingsSbdBalance() string { + if m != nil { + return m.SavingsSbdBalance + } + return "" +} + +func (m *Balance) GetVestingBalance() string { + if m != nil { + return m.VestingBalance + } + return "" +} + +type GetBalancesResponse struct { + Balances []*Balance `protobuf:"bytes,1,rep,name=balances" json:"balances,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error" json:"error,omitempty"` +} + +func (m *GetBalancesResponse) Reset() { *m = GetBalancesResponse{} } +func (m *GetBalancesResponse) String() string { return proto1.CompactTextString(m) } +func (*GetBalancesResponse) ProtoMessage() {} +func (*GetBalancesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *GetBalancesResponse) GetBalances() []*Balance { + if m != nil { + return m.Balances + } + return nil +} + +func (m *GetBalancesResponse) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +type AccountCreateRequest struct { + Account string `protobuf:"bytes,1,opt,name=account" json:"account,omitempty"` + Owner string `protobuf:"bytes,2,opt,name=owner" json:"owner,omitempty"` + Active string `protobuf:"bytes,3,opt,name=active" json:"active,omitempty"` + Posting string `protobuf:"bytes,4,opt,name=posting" json:"posting,omitempty"` + Memo string `protobuf:"bytes,5,opt,name=memo" json:"memo,omitempty"` + Fee string `protobuf:"bytes,6,opt,name=fee" json:"fee,omitempty"` +} + +func (m *AccountCreateRequest) Reset() { *m = AccountCreateRequest{} } +func (m *AccountCreateRequest) String() string { return proto1.CompactTextString(m) } +func (*AccountCreateRequest) ProtoMessage() {} +func (*AccountCreateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *AccountCreateRequest) GetAccount() string { + if m != nil { + return m.Account + } + return "" +} + +func (m *AccountCreateRequest) GetOwner() string { + if m != nil { + return m.Owner + } + return "" +} + +func (m *AccountCreateRequest) GetActive() string { + if m != nil { + return m.Active + } + return "" +} + +func (m *AccountCreateRequest) GetPosting() string { + if m != nil { + return m.Posting + } + return "" +} + +func (m *AccountCreateRequest) GetMemo() string { + if m != nil { + return m.Memo + } + return "" +} + +func (m *AccountCreateRequest) GetFee() string { + if m != nil { + return m.Fee + } + return "" +} + +type BalancesChangedMessage struct { + Balances []*Balance `protobuf:"bytes,1,rep,name=balances" json:"balances,omitempty"` +} + +func (m *BalancesChangedMessage) Reset() { *m = BalancesChangedMessage{} } +func (m *BalancesChangedMessage) String() string { return proto1.CompactTextString(m) } +func (*BalancesChangedMessage) ProtoMessage() {} +func (*BalancesChangedMessage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *BalancesChangedMessage) GetBalances() []*Balance { + if m != nil { + return m.Balances + } + return nil +} + +type GetTrackedAddressesResponse struct { + Accounts []string `protobuf:"bytes,1,rep,name=accounts" json:"accounts,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error" json:"error,omitempty"` +} + +func (m *GetTrackedAddressesResponse) Reset() { *m = GetTrackedAddressesResponse{} } +func (m *GetTrackedAddressesResponse) String() string { return proto1.CompactTextString(m) } +func (*GetTrackedAddressesResponse) ProtoMessage() {} +func (*GetTrackedAddressesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *GetTrackedAddressesResponse) GetAccounts() []string { + if m != nil { + return m.Accounts + } + return nil +} + +func (m *GetTrackedAddressesResponse) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +type SendTransactionResponse struct { + Ok bool `protobuf:"varint,1,opt,name=ok" json:"ok,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error" json:"error,omitempty"` + Response string `protobuf:"bytes,3,opt,name=response" json:"response,omitempty"` +} + +func (m *SendTransactionResponse) Reset() { *m = SendTransactionResponse{} } +func (m *SendTransactionResponse) String() string { return proto1.CompactTextString(m) } +func (*SendTransactionResponse) ProtoMessage() {} +func (*SendTransactionResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +func (m *SendTransactionResponse) GetOk() bool { + if m != nil { + return m.Ok + } + return false +} + +func (m *SendTransactionResponse) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +func (m *SendTransactionResponse) GetResponse() string { + if m != nil { + return m.Response + } + return "" +} + +type Block struct { + Height uint32 `protobuf:"varint,1,opt,name=height" json:"height,omitempty"` + Time int64 `protobuf:"varint,2,opt,name=time" json:"time,omitempty"` + Transactions []*Block_Transaction `protobuf:"bytes,3,rep,name=transactions" json:"transactions,omitempty"` +} + +func (m *Block) Reset() { *m = Block{} } +func (m *Block) String() string { return proto1.CompactTextString(m) } +func (*Block) ProtoMessage() {} +func (*Block) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +func (m *Block) GetHeight() uint32 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *Block) GetTime() int64 { + if m != nil { + return m.Time + } + return 0 +} + +func (m *Block) GetTransactions() []*Block_Transaction { + if m != nil { + return m.Transactions + } + return nil +} + +type Block_Transaction struct { + RefBlockNum uint32 `protobuf:"varint,1,opt,name=ref_block_num,json=refBlockNum" json:"ref_block_num,omitempty"` + RefBlockPrefix uint32 `protobuf:"varint,2,opt,name=ref_block_prefix,json=refBlockPrefix" json:"ref_block_prefix,omitempty"` + Expiration int64 `protobuf:"varint,3,opt,name=expiration" json:"expiration,omitempty"` + Operations string `protobuf:"bytes,4,opt,name=operations" json:"operations,omitempty"` + Signatures []string `protobuf:"bytes,6,rep,name=signatures" json:"signatures,omitempty"` +} + +func (m *Block_Transaction) Reset() { *m = Block_Transaction{} } +func (m *Block_Transaction) String() string { return proto1.CompactTextString(m) } +func (*Block_Transaction) ProtoMessage() {} +func (*Block_Transaction) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10, 0} } + +func (m *Block_Transaction) GetRefBlockNum() uint32 { + if m != nil { + return m.RefBlockNum + } + return 0 +} + +func (m *Block_Transaction) GetRefBlockPrefix() uint32 { + if m != nil { + return m.RefBlockPrefix + } + return 0 +} + +func (m *Block_Transaction) GetExpiration() int64 { + if m != nil { + return m.Expiration + } + return 0 +} + +func (m *Block_Transaction) GetOperations() string { + if m != nil { + return m.Operations + } + return "" +} + +func (m *Block_Transaction) GetSignatures() []string { + if m != nil { + return m.Signatures + } + return nil +} + +type HeadInfo struct { + Height uint32 `protobuf:"varint,1,opt,name=height" json:"height,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id" json:"id,omitempty"` +} + +func (m *HeadInfo) Reset() { *m = HeadInfo{} } +func (m *HeadInfo) String() string { return proto1.CompactTextString(m) } +func (*HeadInfo) ProtoMessage() {} +func (*HeadInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +func (m *HeadInfo) GetHeight() uint32 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *HeadInfo) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +type Empty struct { +} + +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto1.CompactTextString(m) } +func (*Empty) ProtoMessage() {} +func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } + +type TransactionJSON struct { + Json string `protobuf:"bytes,1,opt,name=json" json:"json,omitempty"` +} + +func (m *TransactionJSON) Reset() { *m = TransactionJSON{} } +func (m *TransactionJSON) String() string { return proto1.CompactTextString(m) } +func (*TransactionJSON) ProtoMessage() {} +func (*TransactionJSON) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } + +func (m *TransactionJSON) GetJson() string { + if m != nil { + return m.Json + } + return "" +} + +func init() { + proto1.RegisterType((*OkErrResponse)(nil), "proto.OkErrResponse") + proto1.RegisterType((*AccountCheckRequest)(nil), "proto.AccountCheckRequest") + proto1.RegisterType((*AccountCheckResponse)(nil), "proto.AccountCheckResponse") + proto1.RegisterType((*Accounts)(nil), "proto.Accounts") + proto1.RegisterType((*Balance)(nil), "proto.Balance") + proto1.RegisterType((*GetBalancesResponse)(nil), "proto.GetBalancesResponse") + proto1.RegisterType((*AccountCreateRequest)(nil), "proto.AccountCreateRequest") + proto1.RegisterType((*BalancesChangedMessage)(nil), "proto.BalancesChangedMessage") + proto1.RegisterType((*GetTrackedAddressesResponse)(nil), "proto.GetTrackedAddressesResponse") + proto1.RegisterType((*SendTransactionResponse)(nil), "proto.SendTransactionResponse") + proto1.RegisterType((*Block)(nil), "proto.Block") + proto1.RegisterType((*Block_Transaction)(nil), "proto.Block.Transaction") + proto1.RegisterType((*HeadInfo)(nil), "proto.HeadInfo") + proto1.RegisterType((*Empty)(nil), "proto.Empty") + proto1.RegisterType((*TransactionJSON)(nil), "proto.TransactionJSON") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for NodeCommunications service + +type NodeCommunicationsClient interface { + EventGetHeadInfo(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*HeadInfo, error) + EventAccountCheck(ctx context.Context, in *AccountCheckRequest, opts ...grpc.CallOption) (*AccountCheckResponse, error) + EventAccountCreate(ctx context.Context, in *AccountCreateRequest, opts ...grpc.CallOption) (*OkErrResponse, error) + EventGetBalances(ctx context.Context, in *Accounts, opts ...grpc.CallOption) (*GetBalancesResponse, error) + EventTrackAddresses(ctx context.Context, in *Accounts, opts ...grpc.CallOption) (*OkErrResponse, error) + EventGetTrackedAddresses(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Accounts, error) + EventSendTransactionJSON(ctx context.Context, in *TransactionJSON, opts ...grpc.CallOption) (*SendTransactionResponse, error) + BalanceChanged(ctx context.Context, in *Empty, opts ...grpc.CallOption) (NodeCommunications_BalanceChangedClient, error) + NewBlock(ctx context.Context, in *Empty, opts ...grpc.CallOption) (NodeCommunications_NewBlockClient, error) +} + +type nodeCommunicationsClient struct { + cc *grpc.ClientConn +} + +func NewNodeCommunicationsClient(cc *grpc.ClientConn) NodeCommunicationsClient { + return &nodeCommunicationsClient{cc} +} + +func (c *nodeCommunicationsClient) EventGetHeadInfo(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*HeadInfo, error) { + out := new(HeadInfo) + err := grpc.Invoke(ctx, "/proto.NodeCommunications/EventGetHeadInfo", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nodeCommunicationsClient) EventAccountCheck(ctx context.Context, in *AccountCheckRequest, opts ...grpc.CallOption) (*AccountCheckResponse, error) { + out := new(AccountCheckResponse) + err := grpc.Invoke(ctx, "/proto.NodeCommunications/EventAccountCheck", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nodeCommunicationsClient) EventAccountCreate(ctx context.Context, in *AccountCreateRequest, opts ...grpc.CallOption) (*OkErrResponse, error) { + out := new(OkErrResponse) + err := grpc.Invoke(ctx, "/proto.NodeCommunications/EventAccountCreate", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nodeCommunicationsClient) EventGetBalances(ctx context.Context, in *Accounts, opts ...grpc.CallOption) (*GetBalancesResponse, error) { + out := new(GetBalancesResponse) + err := grpc.Invoke(ctx, "/proto.NodeCommunications/EventGetBalances", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nodeCommunicationsClient) EventTrackAddresses(ctx context.Context, in *Accounts, opts ...grpc.CallOption) (*OkErrResponse, error) { + out := new(OkErrResponse) + err := grpc.Invoke(ctx, "/proto.NodeCommunications/EventTrackAddresses", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nodeCommunicationsClient) EventGetTrackedAddresses(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Accounts, error) { + out := new(Accounts) + err := grpc.Invoke(ctx, "/proto.NodeCommunications/EventGetTrackedAddresses", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nodeCommunicationsClient) EventSendTransactionJSON(ctx context.Context, in *TransactionJSON, opts ...grpc.CallOption) (*SendTransactionResponse, error) { + out := new(SendTransactionResponse) + err := grpc.Invoke(ctx, "/proto.NodeCommunications/EventSendTransactionJSON", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nodeCommunicationsClient) BalanceChanged(ctx context.Context, in *Empty, opts ...grpc.CallOption) (NodeCommunications_BalanceChangedClient, error) { + stream, err := grpc.NewClientStream(ctx, &_NodeCommunications_serviceDesc.Streams[0], c.cc, "/proto.NodeCommunications/BalanceChanged", opts...) + if err != nil { + return nil, err + } + x := &nodeCommunicationsBalanceChangedClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type NodeCommunications_BalanceChangedClient interface { + Recv() (*Balance, error) + grpc.ClientStream +} + +type nodeCommunicationsBalanceChangedClient struct { + grpc.ClientStream +} + +func (x *nodeCommunicationsBalanceChangedClient) Recv() (*Balance, error) { + m := new(Balance) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *nodeCommunicationsClient) NewBlock(ctx context.Context, in *Empty, opts ...grpc.CallOption) (NodeCommunications_NewBlockClient, error) { + stream, err := grpc.NewClientStream(ctx, &_NodeCommunications_serviceDesc.Streams[1], c.cc, "/proto.NodeCommunications/NewBlock", opts...) + if err != nil { + return nil, err + } + x := &nodeCommunicationsNewBlockClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type NodeCommunications_NewBlockClient interface { + Recv() (*Block, error) + grpc.ClientStream +} + +type nodeCommunicationsNewBlockClient struct { + grpc.ClientStream +} + +func (x *nodeCommunicationsNewBlockClient) Recv() (*Block, error) { + m := new(Block) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// Server API for NodeCommunications service + +type NodeCommunicationsServer interface { + EventGetHeadInfo(context.Context, *Empty) (*HeadInfo, error) + EventAccountCheck(context.Context, *AccountCheckRequest) (*AccountCheckResponse, error) + EventAccountCreate(context.Context, *AccountCreateRequest) (*OkErrResponse, error) + EventGetBalances(context.Context, *Accounts) (*GetBalancesResponse, error) + EventTrackAddresses(context.Context, *Accounts) (*OkErrResponse, error) + EventGetTrackedAddresses(context.Context, *Empty) (*Accounts, error) + EventSendTransactionJSON(context.Context, *TransactionJSON) (*SendTransactionResponse, error) + BalanceChanged(*Empty, NodeCommunications_BalanceChangedServer) error + NewBlock(*Empty, NodeCommunications_NewBlockServer) error +} + +func RegisterNodeCommunicationsServer(s *grpc.Server, srv NodeCommunicationsServer) { + s.RegisterService(&_NodeCommunications_serviceDesc, srv) +} + +func _NodeCommunications_EventGetHeadInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeCommunicationsServer).EventGetHeadInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NodeCommunications/EventGetHeadInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeCommunicationsServer).EventGetHeadInfo(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _NodeCommunications_EventAccountCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AccountCheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeCommunicationsServer).EventAccountCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NodeCommunications/EventAccountCheck", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeCommunicationsServer).EventAccountCheck(ctx, req.(*AccountCheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _NodeCommunications_EventAccountCreate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AccountCreateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeCommunicationsServer).EventAccountCreate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NodeCommunications/EventAccountCreate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeCommunicationsServer).EventAccountCreate(ctx, req.(*AccountCreateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _NodeCommunications_EventGetBalances_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Accounts) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeCommunicationsServer).EventGetBalances(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NodeCommunications/EventGetBalances", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeCommunicationsServer).EventGetBalances(ctx, req.(*Accounts)) + } + return interceptor(ctx, in, info, handler) +} + +func _NodeCommunications_EventTrackAddresses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Accounts) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeCommunicationsServer).EventTrackAddresses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NodeCommunications/EventTrackAddresses", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeCommunicationsServer).EventTrackAddresses(ctx, req.(*Accounts)) + } + return interceptor(ctx, in, info, handler) +} + +func _NodeCommunications_EventGetTrackedAddresses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeCommunicationsServer).EventGetTrackedAddresses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NodeCommunications/EventGetTrackedAddresses", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeCommunicationsServer).EventGetTrackedAddresses(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _NodeCommunications_EventSendTransactionJSON_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TransactionJSON) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeCommunicationsServer).EventSendTransactionJSON(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NodeCommunications/EventSendTransactionJSON", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeCommunicationsServer).EventSendTransactionJSON(ctx, req.(*TransactionJSON)) + } + return interceptor(ctx, in, info, handler) +} + +func _NodeCommunications_BalanceChanged_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(Empty) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(NodeCommunicationsServer).BalanceChanged(m, &nodeCommunicationsBalanceChangedServer{stream}) +} + +type NodeCommunications_BalanceChangedServer interface { + Send(*Balance) error + grpc.ServerStream +} + +type nodeCommunicationsBalanceChangedServer struct { + grpc.ServerStream +} + +func (x *nodeCommunicationsBalanceChangedServer) Send(m *Balance) error { + return x.ServerStream.SendMsg(m) +} + +func _NodeCommunications_NewBlock_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(Empty) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(NodeCommunicationsServer).NewBlock(m, &nodeCommunicationsNewBlockServer{stream}) +} + +type NodeCommunications_NewBlockServer interface { + Send(*Block) error + grpc.ServerStream +} + +type nodeCommunicationsNewBlockServer struct { + grpc.ServerStream +} + +func (x *nodeCommunicationsNewBlockServer) Send(m *Block) error { + return x.ServerStream.SendMsg(m) +} + +var _NodeCommunications_serviceDesc = grpc.ServiceDesc{ + ServiceName: "proto.NodeCommunications", + HandlerType: (*NodeCommunicationsServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "EventGetHeadInfo", + Handler: _NodeCommunications_EventGetHeadInfo_Handler, + }, + { + MethodName: "EventAccountCheck", + Handler: _NodeCommunications_EventAccountCheck_Handler, + }, + { + MethodName: "EventAccountCreate", + Handler: _NodeCommunications_EventAccountCreate_Handler, + }, + { + MethodName: "EventGetBalances", + Handler: _NodeCommunications_EventGetBalances_Handler, + }, + { + MethodName: "EventTrackAddresses", + Handler: _NodeCommunications_EventTrackAddresses_Handler, + }, + { + MethodName: "EventGetTrackedAddresses", + Handler: _NodeCommunications_EventGetTrackedAddresses_Handler, + }, + { + MethodName: "EventSendTransactionJSON", + Handler: _NodeCommunications_EventSendTransactionJSON_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "BalanceChanged", + Handler: _NodeCommunications_BalanceChanged_Handler, + ServerStreams: true, + }, + { + StreamName: "NewBlock", + Handler: _NodeCommunications_NewBlock_Handler, + ServerStreams: true, + }, + }, + Metadata: "golos.proto", +} + +func init() { proto1.RegisterFile("golos.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 783 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x6e, 0xeb, 0x44, + 0x10, 0x96, 0x93, 0xe6, 0xe7, 0x4c, 0x9a, 0xa4, 0x67, 0x53, 0x15, 0xcb, 0x47, 0x3a, 0x44, 0x96, + 0xd0, 0x09, 0x5c, 0x44, 0xa5, 0x88, 0x0b, 0xa4, 0x4a, 0xa8, 0x2d, 0x55, 0x00, 0x41, 0x8a, 0xdc, + 0x4a, 0x5c, 0x70, 0x51, 0x39, 0xf6, 0x24, 0x31, 0xa9, 0x77, 0xc3, 0xae, 0x93, 0x96, 0x97, 0xe1, + 0x15, 0x78, 0x00, 0x5e, 0x80, 0x67, 0xe0, 0x69, 0xd0, 0xae, 0x67, 0x1d, 0x27, 0x27, 0xb9, 0xe8, + 0x55, 0xf6, 0x9b, 0xf9, 0xf6, 0xdb, 0x99, 0x6f, 0x3d, 0x1b, 0x68, 0xcd, 0xc4, 0x93, 0x50, 0xc3, + 0xa5, 0x14, 0x99, 0x60, 0x35, 0xf3, 0xe3, 0x7f, 0x0d, 0xed, 0xbb, 0xc5, 0xad, 0x94, 0x01, 0xaa, + 0xa5, 0xe0, 0x0a, 0x59, 0x07, 0x2a, 0x62, 0xe1, 0x3a, 0x7d, 0x67, 0xd0, 0x0c, 0x2a, 0x62, 0xc1, + 0x4e, 0xa1, 0x86, 0x52, 0x0a, 0xe9, 0x56, 0xfa, 0xce, 0xe0, 0x4d, 0x90, 0x03, 0xff, 0x73, 0xe8, + 0x5d, 0x45, 0x91, 0x58, 0xf1, 0xec, 0x66, 0x8e, 0xd1, 0x22, 0xc0, 0x3f, 0x56, 0xa8, 0x32, 0xc6, + 0xe0, 0x88, 0x87, 0x29, 0x9a, 0xed, 0x6f, 0x02, 0xb3, 0xf6, 0xaf, 0xe1, 0x74, 0x9b, 0x4a, 0x07, + 0x69, 0xe1, 0x97, 0x44, 0x65, 0x74, 0x56, 0x0e, 0x0e, 0x1c, 0xd7, 0x87, 0x26, 0x69, 0x28, 0xcd, + 0xd0, 0xba, 0xca, 0x75, 0xfa, 0x55, 0xcd, 0x30, 0xc0, 0xff, 0xcf, 0x81, 0xc6, 0x75, 0xf8, 0x14, + 0xf2, 0x08, 0xf7, 0x55, 0xc1, 0x5c, 0x68, 0x4c, 0xf2, 0x34, 0x29, 0x5b, 0xc8, 0x3e, 0x40, 0x57, + 0x85, 0xeb, 0x84, 0xcf, 0xd4, 0xa3, 0x65, 0x54, 0x0d, 0xa3, 0x43, 0x61, 0x2b, 0xfb, 0x29, 0xb4, + 0xd4, 0x24, 0x2e, 0x48, 0x47, 0x86, 0x04, 0x6a, 0x12, 0x5b, 0xc2, 0x10, 0x7a, 0x56, 0xa9, 0x4c, + 0xac, 0x19, 0xe2, 0x5b, 0x4a, 0xdd, 0x6f, 0xf8, 0x1f, 0xa0, 0xbb, 0x46, 0x95, 0x25, 0x7c, 0x56, + 0x70, 0xeb, 0xf9, 0xc9, 0x14, 0x26, 0xa2, 0xff, 0x2b, 0xf4, 0x46, 0x98, 0x11, 0x52, 0x85, 0x83, + 0x5f, 0x40, 0x93, 0xf6, 0xe5, 0x66, 0xb4, 0x2e, 0x3a, 0xf9, 0xe5, 0x0e, 0x89, 0x1a, 0x14, 0xf9, + 0x03, 0xbe, 0xfe, 0xe5, 0x6c, 0x2e, 0x47, 0x62, 0x98, 0xa1, 0xbd, 0x48, 0x17, 0x1a, 0x61, 0x1e, + 0x27, 0x17, 0x2d, 0xd4, 0x42, 0xe2, 0x99, 0x63, 0x21, 0x64, 0x00, 0x3b, 0x83, 0x7a, 0x18, 0x65, + 0xc9, 0xda, 0x7a, 0x47, 0x48, 0xeb, 0x2c, 0x85, 0xe9, 0x85, 0xfc, 0xb2, 0x50, 0x5f, 0x52, 0x8a, + 0xa9, 0x20, 0x77, 0xcc, 0x9a, 0x9d, 0x40, 0x75, 0x8a, 0xd6, 0x04, 0xbd, 0xf4, 0xbf, 0x83, 0x33, + 0xdb, 0xf6, 0xcd, 0x3c, 0xe4, 0x33, 0x8c, 0x7f, 0x46, 0xa5, 0xc2, 0xd9, 0xab, 0x9a, 0xf7, 0xef, + 0xe0, 0xdd, 0x08, 0xb3, 0x07, 0x19, 0x46, 0x0b, 0x8c, 0xaf, 0xe2, 0x58, 0xa2, 0x52, 0x25, 0x1f, + 0x3d, 0x68, 0x52, 0x77, 0xf6, 0xa3, 0x2a, 0xf0, 0x01, 0xdf, 0x7e, 0x83, 0x4f, 0xee, 0x91, 0xc7, + 0x0f, 0x32, 0xe4, 0x4a, 0x77, 0x2a, 0xf8, 0xeb, 0xe6, 0x47, 0x1f, 0x29, 0x69, 0x07, 0x39, 0x56, + 0x60, 0xff, 0xef, 0x0a, 0xd4, 0xae, 0x9f, 0x44, 0xb4, 0xd0, 0xae, 0xce, 0x31, 0x99, 0xcd, 0xf3, + 0x4b, 0x68, 0x07, 0x84, 0xb4, 0x77, 0x59, 0x92, 0xe6, 0x5f, 0x72, 0x35, 0x30, 0x6b, 0x76, 0x09, + 0xc7, 0xd9, 0xa6, 0x1c, 0xe5, 0x56, 0x8d, 0x27, 0xae, 0xf5, 0x44, 0xeb, 0x0d, 0xcb, 0xf5, 0x6e, + 0xb1, 0xbd, 0x7f, 0x1c, 0x68, 0x95, 0xb2, 0xcc, 0x87, 0xb6, 0xc4, 0xe9, 0xe3, 0x44, 0x6f, 0x7b, + 0xe4, 0xab, 0x94, 0x0a, 0x68, 0x49, 0x9c, 0x1a, 0xa9, 0xf1, 0x2a, 0x65, 0x03, 0x38, 0xd9, 0x70, + 0x96, 0x12, 0xa7, 0xc9, 0x8b, 0xa9, 0xa8, 0x1d, 0x74, 0x2c, 0xed, 0x17, 0x13, 0x65, 0xef, 0x01, + 0xf0, 0x65, 0x99, 0xc8, 0x50, 0x6b, 0x9b, 0x7e, 0xab, 0x41, 0x29, 0xa2, 0xf3, 0x62, 0x89, 0x39, + 0x50, 0x76, 0xb0, 0x36, 0x11, 0x9d, 0x57, 0xc9, 0x8c, 0x87, 0xd9, 0x4a, 0xa2, 0x72, 0xeb, 0xe6, + 0x8a, 0x4a, 0x11, 0xff, 0x02, 0x9a, 0xdf, 0x63, 0x18, 0xff, 0xc0, 0xa7, 0xe2, 0xa0, 0x67, 0x1d, + 0xa8, 0x24, 0x31, 0x5d, 0x42, 0x25, 0x89, 0xfd, 0x06, 0xd4, 0x6e, 0xd3, 0x65, 0xf6, 0xa7, 0xff, + 0x19, 0x74, 0x4b, 0x9d, 0xff, 0x78, 0x7f, 0x37, 0xd6, 0xfe, 0xfe, 0xae, 0x04, 0xb7, 0x0f, 0x88, + 0x5e, 0x5f, 0xfc, 0x7b, 0x04, 0x6c, 0x2c, 0x62, 0xbc, 0x11, 0x69, 0xba, 0xe2, 0x49, 0x44, 0xa5, + 0x7d, 0x09, 0x27, 0xb7, 0x6b, 0xe4, 0xd9, 0x08, 0xb3, 0xa2, 0x84, 0x63, 0x32, 0xdd, 0xe8, 0x7b, + 0x5d, 0x42, 0x45, 0xfa, 0x27, 0x78, 0x6b, 0xb6, 0x94, 0x5f, 0x45, 0xe6, 0x11, 0x6b, 0xcf, 0xab, + 0xea, 0xbd, 0xdb, 0x9b, 0xa3, 0xef, 0x6d, 0x04, 0x6c, 0x4b, 0xcd, 0x8c, 0x31, 0xdb, 0xdd, 0x52, + 0x1e, 0x6e, 0xef, 0x94, 0x92, 0xdb, 0x0f, 0xff, 0xb7, 0x9b, 0x4e, 0xec, 0xc8, 0xb1, 0xee, 0xb6, + 0x8c, 0xf2, 0x6c, 0x99, 0xfb, 0x9e, 0xa3, 0x4b, 0xe8, 0x19, 0x01, 0x33, 0x67, 0xc5, 0x94, 0x7d, + 0xac, 0xb1, 0xff, 0xf8, 0x6f, 0xc0, 0xb5, 0xc7, 0xef, 0x0e, 0xea, 0x01, 0x43, 0x8b, 0x7f, 0x84, + 0x80, 0xb6, 0xee, 0x8c, 0xa4, 0xb9, 0xca, 0x33, 0x22, 0xef, 0xc4, 0xbd, 0xf7, 0x14, 0x3f, 0x34, + 0xc6, 0xe7, 0xd0, 0xa1, 0x06, 0xe9, 0xdd, 0xd9, 0x29, 0x62, 0xe7, 0xb1, 0x39, 0x77, 0xd8, 0x00, + 0x9a, 0x63, 0x7c, 0xce, 0x07, 0x77, 0x9b, 0x7b, 0x5c, 0x1e, 0xc2, 0x73, 0x67, 0x52, 0x37, 0xf0, + 0xab, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x55, 0x92, 0x07, 0x0d, 0x90, 0x07, 0x00, 0x00, +} diff --git a/proto/golos.proto b/proto/golos.proto new file mode 100644 index 0000000..ae0b1cc --- /dev/null +++ b/proto/golos.proto @@ -0,0 +1,109 @@ +syntax = "proto3"; +// based on https://github.com/Appscrunch/Multy-back/ +package proto; + +service NodeCommunications { + rpc EventGetHeadInfo (Empty) returns (HeadInfo); + + rpc EventAccountCheck (AccountCheckRequest) returns (AccountCheckResponse); + + rpc EventAccountCreate (AccountCreateRequest) returns (OkErrResponse); + + rpc EventGetBalances (Accounts) returns (GetBalancesResponse); + + rpc EventTrackAddresses (Accounts) returns (OkErrResponse); + + rpc EventGetTrackedAddresses (Empty) returns (Accounts); + + rpc EventSendTransactionJSON(TransactionJSON) returns (SendTransactionResponse); + + rpc BalanceChanged (Empty) returns (stream Balance); + + rpc NewBlock (Empty) returns (stream Block); +} + +message OkErrResponse { + bool ok = 1; + string error = 2; +} + +message AccountCheckRequest { + string name = 1; +} + +message AccountCheckResponse { + bool exist = 1; + string error = 2; +} + +message Accounts { + repeated string names = 1; +} + +message Balance { + string name = 1; + string balance = 2; + string savings_balance = 3; + string sbd_balance = 4; + string savings_sbd_balance = 5; + string vesting_balance = 6; +} + +message GetBalancesResponse { + repeated Balance balances = 1; + string error = 2; +} + +message AccountCreateRequest { + string account = 1; + string owner = 2; + string active = 3; + string posting = 4; + string memo = 5; + string fee = 6; // Fee is "0.000 GOLOS" format +} + +message BalancesChangedMessage { + repeated Balance balances = 1; +} + +message GetTrackedAddressesResponse { + repeated string accounts = 1; + string error = 2; +} + +message SendTransactionResponse { + bool ok = 1; + string error = 2; + string response = 3; +} + + +message Block { + uint32 height = 1; + int64 time = 2; + + message Transaction { // block has transactions + uint32 ref_block_num = 1; + uint32 ref_block_prefix = 2; + int64 expiration = 3; + + string operations = 4; // IDK how to do variable types for various operations + repeated string signatures = 6; + } + + repeated Transaction transactions = 3; +} + +message HeadInfo { + uint32 height = 1; + string id = 2; // block id has block hash prefix in it +} + +message Empty { + +} + +message TransactionJSON { + string json = 1; +} \ No newline at end of file diff --git a/server.go b/server.go index a3fb6b6..d701056 100644 --- a/server.go +++ b/server.go @@ -1,16 +1,21 @@ +/* + * Copyright 2018 Idealnaya rabota LLC + * Licensed under Multy.io license. + * See LICENSE for details + */ + package main import ( - "encoding/json" "fmt" "log" - "net/http" + "net" "os" - "github.com/Appscrunch/Multy-Back-Golos/api" - - socketio "github.com/googollee/go-socket.io" + "github.com/Appscrunch/Multy-Back-Golos/golos" + pb "github.com/Appscrunch/Multy-Back-Golos/proto" "github.com/urfave/cli" + "google.golang.org/grpc" ) var ( @@ -20,177 +25,24 @@ var ( ) const ( - VERSION = "v0.1" - - ROOM = "golos" - EVENT_CONNECTION = "connection" - EVENT_CREATE_ACCOUNT = "account:create" - EVENT_CHECK_ACCOUNT = "account:check" - EVENT_BALANCE_GET = "balance:get" - EVENT_BALANCE_CHANGED = "balance:changed" - EVENT_TRACK_ADDRESSES = "balance:track:add" - EVENT_GET_TRACKED_ADDRESSES = "balance:track:get" - EVENT_SEND_TRANSACTION = "transaction:send" - EVENT_NEW_BLOCK = "block:new" + VERSION = "v0.2" ) type Server struct { - *api.API -} - -// stringify marshals data struct to a string -// it ignores marshal data, so use it on knownly valid structs -func stringify(data interface{}) string { - s, err := json.Marshal(data) - if err != nil { - log.Printf("stringify: %s", err) - } - return string(s) -} - -// errStr converts nil errors to an empty string -// and non-nil errors to it string representation -func errStr(err error) string { - if err == nil { - return "" - } - return err.Error() + *golos.Server } // NewServer constructs new server handler func NewServer(endpoints []string, net, account, key string) (*Server, error) { - a, err := api.NewAPI(endpoints, net, account, key) + a, err := golos.NewServer(endpoints, net, account, key) return &Server{a}, err } -func unmarshalRequest(data interface{}, v interface{}) error { - return json.Unmarshal([]byte(stringify(data)), v) -} - -func (s *Server) onAccountCheck(data interface{}) string { - req := api.AccountCheckRequest{} - err := unmarshalRequest(data, req) - if err != nil { - return stringify(api.OkErrResponse{ - // account exists by default, so you cannot register one on error - Ok: true, - Error: errStr(err), - }) - } - - exist, err := s.AccountCheck(req.Name) - return stringify(api.OkErrResponse{ - Ok: exist, - Error: errStr(err), - }) -} - -func (s *Server) onAccountCreate(data interface{}) string { - req := api.AccountCreateRequest{} - err := json.Unmarshal(data.([]byte), &req) - if err != nil { - stringify(api.OkErrResponse{ - Ok: false, - Error: errStr(err), - }) - } - err = s.AccountCreate(req.Account, "", req.Owner, req.Active, req.Posting, req.Memo) - return stringify(api.OkErrResponse{ - Ok: err == nil, - Error: errStr(err), - }) - -} - -func (s *Server) onGetBalances(data interface{}) string { - req := api.GetBalancesRequest{} - err := unmarshalRequest(data, &req) - if err != nil { - resp, _ := json.Marshal(api.GetBalancesResponse{ - Balances: nil, - Error: errStr(err), - }) - return string(resp) - } - balances, err := s.GetBalances(req.Accounts) - return stringify(api.GetBalancesResponse{ - Balances: balances, - Error: errStr(err), - }) -} - -func (s *Server) onTrackAddresses(data interface{}) string { - req := api.TrackAddressesRequest{} - err := unmarshalRequest(data, &req) - if err != nil { - return stringify(api.TrackAddressesResponse{ - Ok: false, - Error: errStr(err), - }) - } - err = s.TrackAddresses(req.Adresses) - return stringify(api.TrackAddressesResponse{ - Ok: err == nil, - Error: errStr(err), - }) -} - -func (s *Server) onGetTrackedAddresses(data interface{}) string { - // req := api.GetTrackedAddressesRequest{} - // err := unmarshalRequest(data, &req) - // if err != nil { - // return stringify(api.GetTrackedAddressesResponse{ - // Accounts: nil, - // Error: errStr(err), - // }) - // } - accs, err := s.GetTrackedAddresses() - return stringify(api.GetTrackedAddressesResponse{ - Accounts: accs, - Error: errStr(err), - }) -} - -func (s *Server) onSendTransaction(data interface{}) string { - req := api.SendTransactionRequest{} - err := unmarshalRequest(data, &req) - if err != nil { - return stringify(api.SendTransactionResponse{ - Ok: false, - Error: errStr(err), - }) - } - bResp, err := s.SendTransaction(&req) - return stringify(api.SendTransactionResponse{ - Ok: err == nil, - Error: errStr(err), - Response: bResp, - }) -} - -func (s *Server) broadcastLoop(socket *socketio.Server) { - blockChan := make(chan *api.NewBlockMessage) - balanceChan := make(chan *api.BalancesChangedMessage) - done := make(chan bool) - go s.NewBlockLoop(blockChan, balanceChan, done, 0) - for { - select { - case block := <-blockChan: - log.Printf("broadcast new block: %s", stringify(block)) - socket.BroadcastTo(ROOM, EVENT_NEW_BLOCK, stringify(block)) - case balances := <-balanceChan: - log.Println("broadcast balance change") - socket.BroadcastTo(ROOM, EVENT_BALANCE_CHANGED, stringify(balances)) - } - } - // TODO: graceful shutdown -} - func run(c *cli.Context) error { // check net arguement - net := c.String("net") - if net != "test" && net != "golos" { - return cli.NewExitError(fmt.Sprintf("net must be \"golos\" or \"test\": %s", net), 1) + network := c.String("net") + if network != "test" && network != "golos" { + return cli.NewExitError(fmt.Sprintf("net must be \"golos\" or \"test\": %s", network), 1) } server, err := NewServer( @@ -204,27 +56,18 @@ func run(c *cli.Context) error { } log.Println("new server") - socket, err := socketio.NewServer(nil) + addr := fmt.Sprintf("%s:%s", c.String("host"), c.String("port")) + + // init gRPC server + lis, err := net.Listen("tcp", addr) if err != nil { - log.Fatal(err) + return cli.NewExitError(fmt.Sprintf("failed to listen: %s", err), 2) } - - socket.On(EVENT_CONNECTION, func(so socketio.Socket) { - so.Join(ROOM) - so.On(EVENT_CHECK_ACCOUNT, server.onAccountCheck) - so.On(EVENT_CREATE_ACCOUNT, server.onAccountCreate) - so.On(EVENT_BALANCE_GET, server.onGetBalances) - so.On(EVENT_TRACK_ADDRESSES, server.onTrackAddresses) - so.On(EVENT_GET_TRACKED_ADDRESSES, server.onGetTrackedAddresses) - so.On(EVENT_SEND_TRANSACTION, server.onSendTransaction) - - }) - - http.Handle("/socket.io/", socket) - hostport := fmt.Sprintf("%s:%s", c.String("host"), c.String("port")) - log.Println("Serving at", hostport) - go server.broadcastLoop(socket) - return cli.NewExitError(http.ListenAndServe(hostport, nil), 3) + // Creates a new gRPC server + s := grpc.NewServer() + pb.RegisterNodeCommunicationsServer(s, server) + log.Printf("listening on %s", addr) + return cli.NewExitError(s.Serve(lis), 3) } func main() { diff --git a/vendor/vendor.json b/vendor/vendor.json index a2d8839..284619b 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -141,55 +141,34 @@ "revisionTime": "2017-07-02T00:39:31Z" }, { - "checksumSHA1": "h4FKEw19jw7+Je5OwsISRKIGTm8=", - "path": "github.com/codegangsta/cli", - "revision": "8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff", - "revisionTime": "2018-02-26T03:02:53Z" + "checksumSHA1": "WX1+2gktHcBmE9MGwFSGs7oqexU=", + "path": "github.com/golang/protobuf/proto", + "revision": "e09c5db296004fbe3f74490e84dcd62c3c5ddb1b", + "revisionTime": "2018-03-28T16:31:53Z" }, { - "checksumSHA1": "CAo0j5Q4ZQ09hjIu3DTlBUR/kOs=", - "path": "github.com/googollee/go-engine.io", - "revision": "80ae0e43aca17b4c5a6834999d0f2eaa16b9afda", - "revisionTime": "2017-02-24T22:25:11Z" + "checksumSHA1": "VfkiItDBFFkZluaAMAzJipDXNBY=", + "path": "github.com/golang/protobuf/ptypes", + "revision": "e09c5db296004fbe3f74490e84dcd62c3c5ddb1b", + "revisionTime": "2018-03-28T16:31:53Z" }, { - "checksumSHA1": "Tv1/qmTmjl43MFulf61QbsGuu2c=", - "path": "github.com/googollee/go-engine.io/message", - "revision": "80ae0e43aca17b4c5a6834999d0f2eaa16b9afda", - "revisionTime": "2017-02-24T22:25:11Z" + "checksumSHA1": "yusEaGMuL7OWZSXKJzPEwVC0WqI=", + "path": "github.com/golang/protobuf/ptypes/any", + "revision": "e09c5db296004fbe3f74490e84dcd62c3c5ddb1b", + "revisionTime": "2018-03-28T16:31:53Z" }, { - "checksumSHA1": "Z3Zs8QiMD9WQdAnRNqyrfuElIxg=", - "path": "github.com/googollee/go-engine.io/parser", - "revision": "80ae0e43aca17b4c5a6834999d0f2eaa16b9afda", - "revisionTime": "2017-02-24T22:25:11Z" + "checksumSHA1": "hUjAj0dheFVDl84BAnSWj9qy2iY=", + "path": "github.com/golang/protobuf/ptypes/duration", + "revision": "e09c5db296004fbe3f74490e84dcd62c3c5ddb1b", + "revisionTime": "2018-03-28T16:31:53Z" }, { - "checksumSHA1": "Veyca3YORqrCpon9aIvt0CTB3JI=", - "path": "github.com/googollee/go-engine.io/polling", - "revision": "80ae0e43aca17b4c5a6834999d0f2eaa16b9afda", - "revisionTime": "2017-02-24T22:25:11Z" - }, - { - "checksumSHA1": "WSC+XDEXrzu11rf+gv1Y2N7v/nE=", - "path": "github.com/googollee/go-engine.io/transport", - "revision": "80ae0e43aca17b4c5a6834999d0f2eaa16b9afda", - "revisionTime": "2017-02-24T22:25:11Z" - }, - { - "checksumSHA1": "HKE4UBOwXdi/Qt48b0da4Z/ytSY=", - "path": "github.com/googollee/go-engine.io/websocket", - "revision": "80ae0e43aca17b4c5a6834999d0f2eaa16b9afda", - "revisionTime": "2017-02-24T22:25:11Z" - }, - { - "checksumSHA1": "V6irnAeLCIoI9uONINNdvvlog3o=", - "path": "github.com/googollee/go-socket.io", - "revision": "5447e71f36d394766bf855d5714a487596809f0d", - "revisionTime": "2017-05-25T14:10:29Z", - "tree": true, - "version": "master", - "versionExact": "master" + "checksumSHA1": "O2ItP5rmfrgxPufhjJXbFlXuyL8=", + "path": "github.com/golang/protobuf/ptypes/timestamp", + "revision": "e09c5db296004fbe3f74490e84dcd62c3c5ddb1b", + "revisionTime": "2018-03-28T16:31:53Z" }, { "checksumSHA1": "+1LsRRZKa06yTFg/Tu5NCsyHxOA=", @@ -197,12 +176,6 @@ "revision": "eb925808374e5ca90c83401a40d711dc08c0c0f6", "revisionTime": "2018-03-06T18:15:48Z" }, - { - "checksumSHA1": "abKzFXAn0KDr5U+JON1ZgJ2lUtU=", - "path": "github.com/kr/logfmt", - "revision": "b84e30acd515aadc4b783ad4ff83aff3299bdfe0", - "revisionTime": "2014-02-26T03:06:59Z" - }, { "checksumSHA1": "ljd3FhYRJ91cLZz3wsH9BQQ2JbA=", "path": "github.com/pkg/errors", @@ -226,20 +199,230 @@ { "checksumSHA1": "GtamqiJoL7PGHsN454AoffBFMa8=", "path": "golang.org/x/net/context", - "revision": "892bf7b0c6e2f93b51166bf3882e50277fa5afc6", - "revisionTime": "2018-03-12T19:33:55Z" + "revision": "d41e8174641f662c5a2d1c7a5f9e828788eb8706", + "revisionTime": "2018-04-17T17:58:37Z" + }, + { + "checksumSHA1": "ZxG5VA1rB24+7Q3FIXR+YmUZ1bM=", + "path": "golang.org/x/net/http/httpguts", + "revision": "d41e8174641f662c5a2d1c7a5f9e828788eb8706", + "revisionTime": "2018-04-17T17:58:37Z" + }, + { + "checksumSHA1": "C0DHnAKktfchh6dc6D8Xp/kd2i8=", + "path": "golang.org/x/net/http2", + "revision": "d41e8174641f662c5a2d1c7a5f9e828788eb8706", + "revisionTime": "2018-04-17T17:58:37Z" + }, + { + "checksumSHA1": "LW///cttbVyQo4Qh11kdIt0VMjs=", + "path": "golang.org/x/net/http2/hpack", + "revision": "d41e8174641f662c5a2d1c7a5f9e828788eb8706", + "revisionTime": "2018-04-17T17:58:37Z" + }, + { + "checksumSHA1": "RcrB7tgYS/GMW4QrwVdMOTNqIU8=", + "path": "golang.org/x/net/idna", + "revision": "d41e8174641f662c5a2d1c7a5f9e828788eb8706", + "revisionTime": "2018-04-17T17:58:37Z" + }, + { + "checksumSHA1": "UxahDzW2v4mf/+aFxruuupaoIwo=", + "path": "golang.org/x/net/internal/timeseries", + "revision": "d41e8174641f662c5a2d1c7a5f9e828788eb8706", + "revisionTime": "2018-04-17T17:58:37Z" + }, + { + "checksumSHA1": "3xyuaSNmClqG4YWC7g0isQIbUTc=", + "path": "golang.org/x/net/lex/httplex", + "revision": "d41e8174641f662c5a2d1c7a5f9e828788eb8706", + "revisionTime": "2018-04-17T17:58:37Z" + }, + { + "checksumSHA1": "rJn3m/27kO+2IU6KCCZ74Miby+8=", + "path": "golang.org/x/net/trace", + "revision": "d41e8174641f662c5a2d1c7a5f9e828788eb8706", + "revisionTime": "2018-04-17T17:58:37Z" + }, + { + "checksumSHA1": "CbpjEkkOeh0fdM/V8xKDdI0AA88=", + "path": "golang.org/x/text/secure/bidirule", + "revision": "7922cc490dd5a7dbaa7fd5d6196b49db59ac042f", + "revisionTime": "2018-04-05T08:39:28Z" + }, + { + "checksumSHA1": "ziMb9+ANGRJSSIuxYdRbA+cDRBQ=", + "path": "golang.org/x/text/transform", + "revision": "7922cc490dd5a7dbaa7fd5d6196b49db59ac042f", + "revisionTime": "2018-04-05T08:39:28Z" + }, + { + "checksumSHA1": "w8kDfZ1Ug+qAcVU0v8obbu3aDOY=", + "path": "golang.org/x/text/unicode/bidi", + "revision": "7922cc490dd5a7dbaa7fd5d6196b49db59ac042f", + "revisionTime": "2018-04-05T08:39:28Z" + }, + { + "checksumSHA1": "BCNYmf4Ek93G4lk5x3ucNi/lTwA=", + "path": "golang.org/x/text/unicode/norm", + "revision": "7922cc490dd5a7dbaa7fd5d6196b49db59ac042f", + "revisionTime": "2018-04-05T08:39:28Z" + }, + { + "checksumSHA1": "Tc3BU26zThLzcyqbVtiSEp7EpU8=", + "path": "google.golang.org/genproto/googleapis/rpc/status", + "revision": "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200", + "revisionTime": "2018-04-13T17:58:16Z" + }, + { + "checksumSHA1": "DcMnfUikQvTJS7lTSRAJ/IfnBB0=", + "path": "google.golang.org/grpc", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "XgBf9DGAD5gsvWR3LLqn3cI5uGQ=", + "path": "google.golang.org/grpc/balancer", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "lw+L836hLeH8+//le+C+ycddCCU=", + "path": "google.golang.org/grpc/balancer/base", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "DJ1AtOk4Pu7bqtUMob95Hw8HPNw=", + "path": "google.golang.org/grpc/balancer/roundrobin", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "1nO1ENEg8bNzotnfandK4UNLHvM=", + "path": "google.golang.org/grpc/channelz", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "j8Qs+yfgwYYOtodB/1bSlbzV5rs=", + "path": "google.golang.org/grpc/codes", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "XH2WYcDNwVO47zYShREJjcYXm0Y=", + "path": "google.golang.org/grpc/connectivity", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "KthiDKNPHMeIu967enqtE4NaZzI=", + "path": "google.golang.org/grpc/credentials", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "cfLb+pzWB+Glwp82rgfcEST1mv8=", + "path": "google.golang.org/grpc/encoding", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "LKKkn7EYA+Do9Qwb2/SUKLFNxoo=", + "path": "google.golang.org/grpc/encoding/proto", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "H7SuPUqbPcdbNqgl+k3ohuwMAwE=", + "path": "google.golang.org/grpc/grpclb/grpc_lb_v1/messages", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "ntHev01vgZgeIh5VFRmbLx/BSTo=", + "path": "google.golang.org/grpc/grpclog", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "Qvf3zdmRCSsiM/VoBv0qB/naHtU=", + "path": "google.golang.org/grpc/internal", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "hcuHgKp8W0wIzoCnNfKI8NUss5o=", + "path": "google.golang.org/grpc/keepalive", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "2pqxj+XG5KR1zCFu7YQ0GUZj5hM=", + "path": "google.golang.org/grpc/metadata", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "VvGBoawND0urmYDy11FT+U1IHtU=", + "path": "google.golang.org/grpc/naming", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "n5EgDdBqFMa2KQFhtl+FF/4gIFo=", + "path": "google.golang.org/grpc/peer", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "RVD5FlQonhZC32T8/rXJ3rhhlyY=", + "path": "google.golang.org/grpc/resolver", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "dKoHbjh622EZpteMlQN4vC6X5aU=", + "path": "google.golang.org/grpc/resolver/dns", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "zs9M4xE8Lyg4wvuYvR00XoBxmuw=", + "path": "google.golang.org/grpc/resolver/passthrough", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "YclPgme2gT3S0hTkHVdE1zAxJdo=", + "path": "google.golang.org/grpc/stats", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "FXiovlBmrYdS4QT0Z4nV+x+v5HI=", + "path": "google.golang.org/grpc/status", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "qvArRhlrww5WvRmbyMF2mUfbJew=", + "path": "google.golang.org/grpc/tap", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" + }, + { + "checksumSHA1": "TeKz8JdGP7fk1J1TLYtZ1vcJp/8=", + "path": "google.golang.org/grpc/transport", + "revision": "d27df52a27ae0f6e08b19846f31eaf7d86e6bfa4", + "revisionTime": "2018-04-18T18:25:19Z" }, { "checksumSHA1": "t95/FNK2nGCx3e6IARbO7OrcCuY=", "path": "gopkg.in/tomb.v2", "revision": "d5d1b5820637886def9eef33e03a27a9f166942c", "revisionTime": "2016-12-08T15:16:19Z" - }, - { - "checksumSHA1": "AnKBN2Q4AWaSNb0JyINBQbnpxGM=", - "path": "gopkg.in/yaml.v2", - "revision": "7f97868eec74b32b0982dd158a51a446d1da7eb5", - "revisionTime": "2018-02-23T19:12:37Z" } ], "rootPath": "github.com/Appscrunch/Multy-Back-Golos"