code.vegaprotocol.io/vega@v0.79.0/core/blockchain/abci/local_client.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package abci 17 18 import ( 19 "context" 20 "time" 21 22 tmquery "github.com/cometbft/cometbft/libs/pubsub/query" 23 "github.com/cometbft/cometbft/libs/service" 24 nm "github.com/cometbft/cometbft/node" 25 "github.com/cometbft/cometbft/rpc/client/local" 26 tmctypes "github.com/cometbft/cometbft/rpc/core/types" 27 tmtypes "github.com/cometbft/cometbft/types" 28 ) 29 30 type LocalClient struct { 31 node *local.Local 32 genesisDoc *cachedGenesisDoc 33 } 34 35 func newLocalClient(node service.Service) (*LocalClient, error) { 36 localNode := local.New(node.(*nm.Node)) 37 return &LocalClient{ 38 node: localNode, 39 genesisDoc: newCachedGenesisDoc(), 40 }, nil 41 } 42 43 func (c *LocalClient) SendTransactionAsync(ctx context.Context, bytes []byte) (*tmctypes.ResultBroadcastTx, error) { 44 // Fire off the transaction for consensus 45 res, err := c.node.BroadcastTxAsync(ctx, bytes) 46 if err != nil { 47 return nil, err 48 } 49 return res, nil 50 } 51 52 func (c *LocalClient) SendTransactionSync(ctx context.Context, bytes []byte) (*tmctypes.ResultBroadcastTx, error) { 53 // Fire off the transaction for consensus 54 return c.node.BroadcastTxSync(ctx, bytes) 55 } 56 57 func (c *LocalClient) SendTransactionCommit(ctx context.Context, bytes []byte) (*tmctypes.ResultBroadcastTxCommit, error) { 58 // Fire off the transaction for consensus 59 return c.node.BroadcastTxCommit(ctx, bytes) 60 } 61 62 func (c *LocalClient) CheckTransaction(ctx context.Context, bytes []byte) (*tmctypes.ResultCheckTx, error) { 63 return c.node.CheckTx(ctx, bytes) 64 } 65 66 // GetGenesisTime retrieves the genesis time from the blockchain. 67 func (c *LocalClient) GetGenesisTime(ctx context.Context) (genesisTime time.Time, err error) { 68 res, err := c.genesisDoc.Get(ctx, c.node) 69 if err != nil { 70 return time.Time{}, err 71 } 72 return res.GenesisTime.UTC(), nil 73 } 74 75 // GetChainID retrieves the chainID from the blockchain. 76 func (c *LocalClient) GetChainID(ctx context.Context) (chainID string, err error) { 77 res, err := c.genesisDoc.Get(ctx, c.node) 78 if err != nil { 79 return "", err 80 } 81 return res.ChainID, nil 82 } 83 84 // GetStatus returns the current status of the chain. 85 func (c *LocalClient) GetStatus(ctx context.Context) (status *tmctypes.ResultStatus, err error) { 86 return c.node.Status(ctx) 87 } 88 89 // GetNetworkInfo return information of the current network. 90 func (c *LocalClient) GetNetworkInfo(ctx context.Context) (netInfo *tmctypes.ResultNetInfo, err error) { 91 return c.node.NetInfo(ctx) 92 } 93 94 // GetUnconfirmedTxCount return the current count of unconfirmed transactions. 95 func (c *LocalClient) GetUnconfirmedTxCount(ctx context.Context) (count int, err error) { 96 res, err := c.node.NumUnconfirmedTxs(ctx) 97 if err != nil { 98 return 0, err 99 } 100 return res.Count, err 101 } 102 103 // Health returns the result of the health endpoint of the chain. 104 func (c *LocalClient) Health(ctx context.Context) (*tmctypes.ResultHealth, error) { 105 return c.node.Health(ctx) 106 } 107 108 func (c *LocalClient) Validators(ctx context.Context, height *int64) ([]*tmtypes.Validator, error) { 109 res, err := c.node.Validators(ctx, height, nil, nil) 110 if err != nil { 111 return nil, err 112 } 113 return res.Validators, nil 114 } 115 116 func (c *LocalClient) Genesis(ctx context.Context) (*tmtypes.GenesisDoc, error) { 117 res, err := c.genesisDoc.Get(ctx, c.node) 118 if err != nil { 119 return nil, err 120 } 121 return res, nil 122 } 123 124 func (c *LocalClient) GenesisValidators(ctx context.Context) ([]*tmtypes.Validator, error) { 125 gen, err := c.Genesis(ctx) 126 if err != nil { 127 return nil, err 128 } 129 130 validators := make([]*tmtypes.Validator, 0, len(gen.Validators)) 131 for _, v := range gen.Validators { 132 validators = append(validators, &tmtypes.Validator{ 133 Address: v.Address, 134 PubKey: v.PubKey, 135 VotingPower: v.Power, 136 }) 137 } 138 139 return validators, nil 140 } 141 142 // Subscribe subscribes to any event matching query (https://godoc.org/github.com/cometbft/cometbft/types#pkg-constants). 143 // Subscribe will call fn each time it receives an event from the node. 144 // The function returns nil when the context is canceled or when fn returns an error. 145 func (c *LocalClient) Subscribe(ctx context.Context, fn func(tmctypes.ResultEvent) error, queries ...string) error { 146 if err := c.node.Start(); err != nil { 147 return err 148 } 149 defer c.node.Stop() 150 151 errCh := make(chan error) 152 153 for _, query := range queries { 154 q, err := tmquery.New(query) 155 if err != nil { 156 return err 157 } 158 159 // For subscription we use "vega" as the client name but it's ignored by the implementation. 160 // 10 is the channel capacity which is absolutely arbitraty. 161 out, err := c.node.Subscribe(ctx, "vega", q.String(), 10) 162 if err != nil { 163 return err 164 } 165 166 go func() { 167 for res := range out { 168 if err := fn(res); err != nil { 169 errCh <- err 170 return 171 } 172 } 173 }() 174 } 175 defer c.node.UnsubscribeAll(context.Background(), "vega") 176 177 return <-errCh 178 } 179 180 func (c *LocalClient) Start() error { 181 return nil // Nothing to do for this client type. 182 }