github.com/okex/exchain@v1.8.0/libs/tendermint/lite2/rpc/client.go (about) 1 package rpc 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/sha256" 7 "errors" 8 "fmt" 9 "strings" 10 "time" 11 12 "github.com/okex/exchain/libs/tendermint/mempool" 13 14 "github.com/okex/exchain/libs/tendermint/crypto/merkle" 15 tmbytes "github.com/okex/exchain/libs/tendermint/libs/bytes" 16 service "github.com/okex/exchain/libs/tendermint/libs/service" 17 lite "github.com/okex/exchain/libs/tendermint/lite2" 18 rpcclient "github.com/okex/exchain/libs/tendermint/rpc/client" 19 ctypes "github.com/okex/exchain/libs/tendermint/rpc/core/types" 20 rpctypes "github.com/okex/exchain/libs/tendermint/rpc/jsonrpc/types" 21 "github.com/okex/exchain/libs/tendermint/types" 22 ) 23 24 var errNegOrZeroHeight = errors.New("negative or zero height") 25 26 // Client is an RPC client, which uses lite#Client to verify data (if it can be 27 // proved!). 28 type Client struct { 29 service.BaseService 30 31 next rpcclient.Client 32 lc *lite.Client 33 prt *merkle.ProofRuntime 34 } 35 36 func (c *Client) GetUnconfirmedTxByHash(hash [sha256.Size]byte) (types.Tx, error) { 37 return nil, mempool.ErrNoSuchTx 38 } 39 40 var _ rpcclient.Client = (*Client)(nil) 41 42 // NewClient returns a new client. 43 func NewClient(next rpcclient.Client, lc *lite.Client) *Client { 44 c := &Client{ 45 next: next, 46 lc: lc, 47 prt: defaultProofRuntime(), 48 } 49 c.BaseService = *service.NewBaseService(nil, "Client", c) 50 return c 51 } 52 53 func (c *Client) OnStart() error { 54 if !c.next.IsRunning() { 55 return c.next.Start() 56 } 57 return nil 58 } 59 60 func (c *Client) OnStop() { 61 if c.next.IsRunning() { 62 c.next.Stop() 63 } 64 } 65 66 func (c *Client) Status() (*ctypes.ResultStatus, error) { 67 return c.next.Status() 68 } 69 70 func (c *Client) ABCIInfo() (*ctypes.ResultABCIInfo, error) { 71 return c.next.ABCIInfo() 72 } 73 74 func (c *Client) ABCIQuery(path string, data tmbytes.HexBytes) (*ctypes.ResultABCIQuery, error) { 75 return c.ABCIQueryWithOptions(path, data, rpcclient.DefaultABCIQueryOptions) 76 } 77 78 // GetWithProofOptions is useful if you want full access to the ABCIQueryOptions. 79 // XXX Usage of path? It's not used, and sometimes it's /, sometimes /key, sometimes /store. 80 func (c *Client) ABCIQueryWithOptions(path string, data tmbytes.HexBytes, 81 opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 82 83 res, err := c.next.ABCIQueryWithOptions(path, data, opts) 84 if err != nil { 85 return nil, err 86 } 87 resp := res.Response 88 89 // Validate the response. 90 if resp.IsErr() { 91 return nil, fmt.Errorf("err response code: %v", resp.Code) 92 } 93 if len(resp.Key) == 0 || resp.Proof == nil { 94 return nil, errors.New("empty tree") 95 } 96 if resp.Height <= 0 { 97 return nil, errNegOrZeroHeight 98 } 99 100 // Update the light client if we're behind. 101 // NOTE: AppHash for height H is in header H+1. 102 h, err := c.updateLiteClientIfNeededTo(resp.Height + 1) 103 if err != nil { 104 return nil, err 105 } 106 107 // Validate the value proof against the trusted header. 108 if resp.Value != nil { 109 // Value exists 110 // XXX How do we encode the key into a string... 111 storeName, err := parseQueryStorePath(path) 112 if err != nil { 113 return nil, err 114 } 115 kp := merkle.KeyPath{} 116 kp = kp.AppendKey([]byte(storeName), merkle.KeyEncodingURL) 117 kp = kp.AppendKey(resp.Key, merkle.KeyEncodingURL) 118 err = c.prt.VerifyValue(resp.Proof, h.AppHash, kp.String(), resp.Value) 119 if err != nil { 120 return nil, fmt.Errorf("verify value proof: %w", err) 121 } 122 return &ctypes.ResultABCIQuery{Response: resp}, nil 123 } 124 125 // OR validate the ansence proof against the trusted header. 126 // XXX How do we encode the key into a string... 127 err = c.prt.VerifyAbsence(resp.Proof, h.AppHash, string(resp.Key)) 128 if err != nil { 129 return nil, fmt.Errorf("verify absence proof: %w", err) 130 } 131 return &ctypes.ResultABCIQuery{Response: resp}, nil 132 } 133 134 func (c *Client) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { 135 return c.next.BroadcastTxCommit(tx) 136 } 137 138 func (c *Client) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 139 return c.next.BroadcastTxAsync(tx) 140 } 141 142 func (c *Client) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 143 return c.next.BroadcastTxSync(tx) 144 } 145 146 func (c *Client) UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error) { 147 return c.next.UnconfirmedTxs(limit) 148 } 149 150 func (c *Client) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) { 151 return c.next.NumUnconfirmedTxs() 152 } 153 154 func (c *Client) UserUnconfirmedTxs(address string, limit int) (*ctypes.ResultUserUnconfirmedTxs, error) { 155 return c.next.UserUnconfirmedTxs(address, limit) 156 } 157 158 func (c *Client) UserNumUnconfirmedTxs(address string) (*ctypes.ResultUserUnconfirmedTxs, error) { 159 return c.next.UserNumUnconfirmedTxs(address) 160 } 161 162 func (c *Client) GetAddressList() (*ctypes.ResultUnconfirmedAddresses, error) { 163 return c.next.GetAddressList() 164 } 165 166 func (c *Client) GetPendingNonce(address string) (*ctypes.ResultPendingNonce, bool) { 167 return c.next.GetPendingNonce(address) 168 } 169 170 func (c *Client) NetInfo() (*ctypes.ResultNetInfo, error) { 171 return c.next.NetInfo() 172 } 173 174 func (c *Client) DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) { 175 return c.next.DumpConsensusState() 176 } 177 178 func (c *Client) ConsensusState() (*ctypes.ResultConsensusState, error) { 179 return c.next.ConsensusState() 180 } 181 182 func (c *Client) ConsensusParams(height *int64) (*ctypes.ResultConsensusParams, error) { 183 res, err := c.next.ConsensusParams(height) 184 if err != nil { 185 return nil, err 186 } 187 188 // Validate res. 189 if err := res.ConsensusParams.Validate(); err != nil { 190 return nil, err 191 } 192 if res.BlockHeight <= 0 { 193 return nil, errNegOrZeroHeight 194 } 195 196 // Update the light client if we're behind. 197 h, err := c.updateLiteClientIfNeededTo(res.BlockHeight) 198 if err != nil { 199 return nil, err 200 } 201 202 // Verify hash. 203 if cH, tH := res.ConsensusParams.Hash(), h.ConsensusHash; !bytes.Equal(cH, tH) { 204 return nil, fmt.Errorf("params hash %X does not match trusted hash %X", 205 cH, tH) 206 } 207 208 return res, nil 209 } 210 211 func (c *Client) Health() (*ctypes.ResultHealth, error) { 212 return c.next.Health() 213 } 214 215 func (c *Client) LatestBlockNumber() (int64, error) { 216 info, err := c.BlockchainInfo(0, 0) 217 if err != nil { 218 return 0, err 219 } 220 return info.LastHeight, nil 221 } 222 223 // BlockchainInfo calls rpcclient#BlockchainInfo and then verifies every header 224 // returned. 225 func (c *Client) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) { 226 res, err := c.next.BlockchainInfo(minHeight, maxHeight) 227 if err != nil { 228 return nil, err 229 } 230 231 // Validate res. 232 for i, meta := range res.BlockMetas { 233 if meta == nil { 234 return nil, fmt.Errorf("nil block meta %d", i) 235 } 236 if err := meta.ValidateBasic(); err != nil { 237 return nil, fmt.Errorf("invalid block meta %d: %w", i, err) 238 } 239 } 240 241 // Update the light client if we're behind. 242 if len(res.BlockMetas) > 0 { 243 lastHeight := res.BlockMetas[len(res.BlockMetas)-1].Header.Height 244 if _, err := c.updateLiteClientIfNeededTo(lastHeight); err != nil { 245 return nil, err 246 } 247 } 248 249 // Verify each of the BlockMetas. 250 for _, meta := range res.BlockMetas { 251 h, err := c.lc.TrustedHeader(meta.Header.Height) 252 if err != nil { 253 return nil, fmt.Errorf("trusted header %d: %w", meta.Header.Height, err) 254 } 255 if bmH, tH := meta.Header.Hash(), h.Hash(); !bytes.Equal(bmH, tH) { 256 return nil, fmt.Errorf("block meta header %X does not match with trusted header %X", 257 bmH, tH) 258 } 259 } 260 261 return res, nil 262 } 263 264 func (c *Client) Genesis() (*ctypes.ResultGenesis, error) { 265 return c.next.Genesis() 266 } 267 268 // Block calls rpcclient#Block and then verifies the result. 269 func (c *Client) Block(height *int64) (*ctypes.ResultBlock, error) { 270 res, err := c.next.Block(height) 271 if err != nil { 272 return nil, err 273 } 274 275 // Validate res. 276 if err := res.BlockID.ValidateBasic(); err != nil { 277 return nil, err 278 } 279 if err := res.Block.ValidateBasic(); err != nil { 280 return nil, err 281 } 282 if bmH, bH := res.BlockID.Hash, res.Block.Hash(); !bytes.Equal(bmH, bH) { 283 return nil, fmt.Errorf("blockID %X does not match with block %X", 284 bmH, bH) 285 } 286 287 // Update the light client if we're behind. 288 h, err := c.updateLiteClientIfNeededTo(res.Block.Height) 289 if err != nil { 290 return nil, err 291 } 292 293 // Verify block. 294 if bH, tH := res.Block.Hash(), h.Hash(); !bytes.Equal(bH, tH) { 295 return nil, fmt.Errorf("block header %X does not match with trusted header %X", 296 bH, tH) 297 } 298 299 return res, nil 300 } 301 302 // Block calls rpcclient#Block and then verifies the result. 303 func (c *Client) BlockInfo(height *int64) (*types.BlockMeta, error) { 304 res, err := c.next.BlockInfo(height) 305 if err != nil { 306 return nil, err 307 } 308 309 // Validate res. 310 if err := res.Header.ValidateBasic(); err != nil { 311 return nil, err 312 } 313 314 return res, nil 315 } 316 317 func (c *Client) BlockResults(height *int64) (*ctypes.ResultBlockResults, error) { 318 res, err := c.next.BlockResults(height) 319 if err != nil { 320 return nil, err 321 } 322 323 // Validate res. 324 if res.Height <= 0 { 325 return nil, errNegOrZeroHeight 326 } 327 328 // Update the light client if we're behind. 329 h, err := c.updateLiteClientIfNeededTo(res.Height + 1) 330 if err != nil { 331 return nil, err 332 } 333 334 // Verify block results. 335 results := types.NewResults(res.TxsResults) 336 if rH, tH := results.Hash(), h.LastResultsHash; !bytes.Equal(rH, tH) { 337 return nil, fmt.Errorf("last results %X does not match with trusted last results %X", 338 rH, tH) 339 } 340 341 return res, nil 342 } 343 344 func (c *Client) Commit(height *int64) (*ctypes.ResultCommit, error) { 345 res, err := c.next.Commit(height) 346 if err != nil { 347 return nil, err 348 } 349 350 // Validate res. 351 if err := res.SignedHeader.ValidateBasic(c.lc.ChainID()); err != nil { 352 return nil, err 353 } 354 if res.Height <= 0 { 355 return nil, errNegOrZeroHeight 356 } 357 358 // Update the light client if we're behind. 359 h, err := c.updateLiteClientIfNeededTo(res.Height) 360 if err != nil { 361 return nil, err 362 } 363 364 // Verify commit. 365 if rH, tH := res.Hash(), h.Hash(); !bytes.Equal(rH, tH) { 366 return nil, fmt.Errorf("header %X does not match with trusted header %X", 367 rH, tH) 368 } 369 370 return res, nil 371 } 372 373 // Tx calls rpcclient#Tx method and then verifies the proof if such was 374 // requested. 375 func (c *Client) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) { 376 res, err := c.next.Tx(hash, prove) 377 if err != nil || !prove { 378 return res, err 379 } 380 381 // Validate res. 382 if res.Height <= 0 { 383 return nil, errNegOrZeroHeight 384 } 385 386 // Update the light client if we're behind. 387 h, err := c.updateLiteClientIfNeededTo(res.Height) 388 if err != nil { 389 return nil, err 390 } 391 392 // Validate the proof. 393 return res, res.Proof.Validate(h.DataHash, res.Height) 394 } 395 396 func (c *Client) TxSearch(query string, prove bool, page, perPage int, orderBy string) ( 397 *ctypes.ResultTxSearch, error) { 398 return c.next.TxSearch(query, prove, page, perPage, orderBy) 399 } 400 401 // Validators fetches and verifies validators. 402 // 403 // WARNING: only full validator sets are verified (when length of validators is 404 // less than +perPage+. +perPage+ default is 30, max is 100). 405 func (c *Client) Validators(height *int64, page, perPage int) (*ctypes.ResultValidators, error) { 406 res, err := c.next.Validators(height, page, perPage) 407 if err != nil { 408 return nil, err 409 } 410 411 // Validate res. 412 if res.BlockHeight <= 0 { 413 return nil, errNegOrZeroHeight 414 } 415 416 // Update the light client if we're behind. 417 h, err := c.updateLiteClientIfNeededTo(res.BlockHeight) 418 if err != nil { 419 return nil, err 420 } 421 422 // Verify validators. 423 if res.Count <= res.Total { 424 if rH, tH := types.NewValidatorSet(res.Validators).Hash(*height), h.ValidatorsHash; !bytes.Equal(rH, tH) { 425 return nil, fmt.Errorf("validators %X does not match with trusted validators %X", 426 rH, tH) 427 } 428 } 429 430 return res, nil 431 } 432 433 func (c *Client) BroadcastEvidence(ev types.Evidence) (*ctypes.ResultBroadcastEvidence, error) { 434 return c.next.BroadcastEvidence(ev) 435 } 436 437 func (c *Client) Subscribe(ctx context.Context, subscriber, query string, 438 outCapacity ...int) (out <-chan ctypes.ResultEvent, err error) { 439 return c.next.Subscribe(ctx, subscriber, query, outCapacity...) 440 } 441 442 func (c *Client) Unsubscribe(ctx context.Context, subscriber, query string) error { 443 return c.next.Unsubscribe(ctx, subscriber, query) 444 } 445 446 func (c *Client) UnsubscribeAll(ctx context.Context, subscriber string) error { 447 return c.next.UnsubscribeAll(ctx, subscriber) 448 } 449 450 func (c *Client) updateLiteClientIfNeededTo(height int64) (*types.SignedHeader, error) { 451 h, err := c.lc.VerifyHeaderAtHeight(height, time.Now()) 452 if err != nil { 453 return nil, fmt.Errorf("failed to update light client to %d: %w", height, err) 454 } 455 return h, nil 456 } 457 458 func (c *Client) RegisterOpDecoder(typ string, dec merkle.OpDecoder) { 459 c.prt.RegisterOpDecoder(typ, dec) 460 } 461 462 // SubscribeWS subscribes for events using the given query and remote address as 463 // a subscriber, but does not verify responses (UNSAFE)! 464 // TODO: verify data 465 func (c *Client) SubscribeWS(ctx *rpctypes.Context, query string) (*ctypes.ResultSubscribe, error) { 466 out, err := c.next.Subscribe(context.Background(), ctx.RemoteAddr(), query) 467 if err != nil { 468 return nil, err 469 } 470 471 go func() { 472 for { 473 select { 474 case resultEvent := <-out: 475 // We should have a switch here that performs a validation 476 // depending on the event's type. 477 ctx.WSConn.TryWriteRPCResponse( 478 rpctypes.NewRPCSuccessResponse( 479 ctx.WSConn.Codec(), 480 rpctypes.JSONRPCStringID(fmt.Sprintf("%v#event", ctx.JSONReq.ID)), 481 resultEvent, 482 )) 483 case <-c.Quit(): 484 return 485 } 486 } 487 }() 488 489 return &ctypes.ResultSubscribe{}, nil 490 } 491 492 // UnsubscribeWS calls original client's Unsubscribe using remote address as a 493 // subscriber. 494 func (c *Client) UnsubscribeWS(ctx *rpctypes.Context, query string) (*ctypes.ResultUnsubscribe, error) { 495 err := c.next.Unsubscribe(context.Background(), ctx.RemoteAddr(), query) 496 if err != nil { 497 return nil, err 498 } 499 return &ctypes.ResultUnsubscribe{}, nil 500 } 501 502 // UnsubscribeAllWS calls original client's UnsubscribeAll using remote address 503 // as a subscriber. 504 func (c *Client) UnsubscribeAllWS(ctx *rpctypes.Context) (*ctypes.ResultUnsubscribe, error) { 505 err := c.next.UnsubscribeAll(context.Background(), ctx.RemoteAddr()) 506 if err != nil { 507 return nil, err 508 } 509 return &ctypes.ResultUnsubscribe{}, nil 510 } 511 512 func parseQueryStorePath(path string) (storeName string, err error) { 513 if !strings.HasPrefix(path, "/") { 514 return "", errors.New("expected path to start with /") 515 } 516 517 paths := strings.SplitN(path[1:], "/", 3) 518 switch { 519 case len(paths) != 3: 520 return "", errors.New("expected format like /store/<storeName>/key") 521 case paths[0] != "store": 522 return "", errors.New("expected format like /store/<storeName>/key") 523 case paths[2] != "key": 524 return "", errors.New("expected format like /store/<storeName>/key") 525 } 526 527 return paths[1], nil 528 }