github.com/516108736/tendermint@v0.36.0/light/rpc/client.go (about) 1 package rpc 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "time" 9 10 "github.com/gogo/protobuf/proto" 11 12 abci "github.com/tendermint/tendermint/abci/types" 13 "github.com/tendermint/tendermint/crypto/merkle" 14 tmbytes "github.com/tendermint/tendermint/libs/bytes" 15 tmmath "github.com/tendermint/tendermint/libs/math" 16 service "github.com/tendermint/tendermint/libs/service" 17 rpcclient "github.com/tendermint/tendermint/rpc/client" 18 ctypes "github.com/tendermint/tendermint/rpc/core/types" 19 rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" 20 "github.com/tendermint/tendermint/types" 21 ) 22 23 var errNegOrZeroHeight = errors.New("negative or zero height") 24 25 // KeyPathFunc builds a merkle path out of the given path and key. 26 type KeyPathFunc func(path string, key []byte) (merkle.KeyPath, error) 27 28 // LightClient is an interface that contains functionality needed by Client from the light client. 29 //go:generate mockery --case underscore --name LightClient 30 type LightClient interface { 31 ChainID() string 32 Update(ctx context.Context, now time.Time) (*types.LightBlock, error) 33 VerifyLightBlockAtHeight(ctx context.Context, height int64, now time.Time) (*types.LightBlock, error) 34 TrustedLightBlock(height int64) (*types.LightBlock, error) 35 } 36 37 // Client is an RPC client, which uses light#Client to verify data (if it can 38 // be proved!). merkle.DefaultProofRuntime is used to verify values returned by 39 // ABCIQuery. 40 type Client struct { 41 service.BaseService 42 43 next rpcclient.Client 44 lc LightClient 45 // Proof runtime used to verify values returned by ABCIQuery 46 prt *merkle.ProofRuntime 47 keyPathFn KeyPathFunc 48 } 49 50 var _ rpcclient.Client = (*Client)(nil) 51 52 // Option allow you to tweak Client. 53 type Option func(*Client) 54 55 // KeyPathFn option can be used to set a function, which parses a given path 56 // and builds the merkle path for the prover. It must be provided if you want 57 // to call ABCIQuery or ABCIQueryWithOptions. 58 func KeyPathFn(fn KeyPathFunc) Option { 59 return func(c *Client) { 60 c.keyPathFn = fn 61 } 62 } 63 64 // NewClient returns a new client. 65 func NewClient(next rpcclient.Client, lc LightClient, opts ...Option) *Client { 66 c := &Client{ 67 next: next, 68 lc: lc, 69 prt: merkle.DefaultProofRuntime(), 70 } 71 c.BaseService = *service.NewBaseService(nil, "Client", c) 72 for _, o := range opts { 73 o(c) 74 } 75 return c 76 } 77 78 func (c *Client) OnStart() error { 79 if !c.next.IsRunning() { 80 return c.next.Start() 81 } 82 return nil 83 } 84 85 func (c *Client) OnStop() { 86 if c.next.IsRunning() { 87 if err := c.next.Stop(); err != nil { 88 c.Logger.Error("Error stopping on next", "err", err) 89 } 90 } 91 } 92 93 func (c *Client) Status(ctx context.Context) (*ctypes.ResultStatus, error) { 94 return c.next.Status(ctx) 95 } 96 97 func (c *Client) ABCIInfo(ctx context.Context) (*ctypes.ResultABCIInfo, error) { 98 return c.next.ABCIInfo(ctx) 99 } 100 101 // ABCIQuery requests proof by default. 102 func (c *Client) ABCIQuery(ctx context.Context, path string, data tmbytes.HexBytes) (*ctypes.ResultABCIQuery, error) { 103 return c.ABCIQueryWithOptions(ctx, path, data, rpcclient.DefaultABCIQueryOptions) 104 } 105 106 // ABCIQueryWithOptions returns an error if opts.Prove is false. 107 func (c *Client) ABCIQueryWithOptions(ctx context.Context, path string, data tmbytes.HexBytes, 108 opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 109 110 // always request the proof 111 opts.Prove = true 112 113 res, err := c.next.ABCIQueryWithOptions(ctx, path, data, opts) 114 if err != nil { 115 return nil, err 116 } 117 resp := res.Response 118 119 // Validate the response. 120 if resp.IsErr() { 121 return nil, fmt.Errorf("err response code: %v", resp.Code) 122 } 123 if len(resp.Key) == 0 { 124 return nil, errors.New("empty key") 125 } 126 if resp.ProofOps == nil || len(resp.ProofOps.Ops) == 0 { 127 return nil, errors.New("no proof ops") 128 } 129 if resp.Height <= 0 { 130 return nil, errNegOrZeroHeight 131 } 132 133 // Update the light client if we're behind. 134 // NOTE: AppHash for height H is in header H+1. 135 nextHeight := resp.Height + 1 136 l, err := c.updateLightClientIfNeededTo(ctx, &nextHeight) 137 if err != nil { 138 return nil, err 139 } 140 141 // Validate the value proof against the trusted header. 142 if resp.Value != nil { 143 // 1) build a Merkle key path from path and resp.Key 144 if c.keyPathFn == nil { 145 return nil, errors.New("please configure Client with KeyPathFn option") 146 } 147 148 kp, err := c.keyPathFn(path, resp.Key) 149 if err != nil { 150 return nil, fmt.Errorf("can't build merkle key path: %w", err) 151 } 152 153 // 2) verify value 154 err = c.prt.VerifyValue(resp.ProofOps, l.AppHash, kp.String(), resp.Value) 155 if err != nil { 156 return nil, fmt.Errorf("verify value proof: %w", err) 157 } 158 } else { // OR validate the absence proof against the trusted header. 159 err = c.prt.VerifyAbsence(resp.ProofOps, l.AppHash, string(resp.Key)) 160 if err != nil { 161 return nil, fmt.Errorf("verify absence proof: %w", err) 162 } 163 } 164 165 return &ctypes.ResultABCIQuery{Response: resp}, nil 166 } 167 168 func (c *Client) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { 169 return c.next.BroadcastTxCommit(ctx, tx) 170 } 171 172 func (c *Client) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 173 return c.next.BroadcastTxAsync(ctx, tx) 174 } 175 176 func (c *Client) BroadcastTxSync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 177 return c.next.BroadcastTxSync(ctx, tx) 178 } 179 180 func (c *Client) UnconfirmedTxs(ctx context.Context, limit *int) (*ctypes.ResultUnconfirmedTxs, error) { 181 return c.next.UnconfirmedTxs(ctx, limit) 182 } 183 184 func (c *Client) NumUnconfirmedTxs(ctx context.Context) (*ctypes.ResultUnconfirmedTxs, error) { 185 return c.next.NumUnconfirmedTxs(ctx) 186 } 187 188 func (c *Client) CheckTx(ctx context.Context, tx types.Tx) (*ctypes.ResultCheckTx, error) { 189 return c.next.CheckTx(ctx, tx) 190 } 191 192 func (c *Client) NetInfo(ctx context.Context) (*ctypes.ResultNetInfo, error) { 193 return c.next.NetInfo(ctx) 194 } 195 196 func (c *Client) DumpConsensusState(ctx context.Context) (*ctypes.ResultDumpConsensusState, error) { 197 return c.next.DumpConsensusState(ctx) 198 } 199 200 func (c *Client) ConsensusState(ctx context.Context) (*ctypes.ResultConsensusState, error) { 201 return c.next.ConsensusState(ctx) 202 } 203 204 func (c *Client) ConsensusParams(ctx context.Context, height *int64) (*ctypes.ResultConsensusParams, error) { 205 res, err := c.next.ConsensusParams(ctx, height) 206 if err != nil { 207 return nil, err 208 } 209 210 // Validate res. 211 if err := types.ValidateConsensusParams(res.ConsensusParams); err != nil { 212 return nil, err 213 } 214 if res.BlockHeight <= 0 { 215 return nil, errNegOrZeroHeight 216 } 217 218 // Update the light client if we're behind. 219 l, err := c.updateLightClientIfNeededTo(ctx, &res.BlockHeight) 220 if err != nil { 221 return nil, err 222 } 223 224 // Verify hash. 225 if cH, tH := types.HashConsensusParams(res.ConsensusParams), l.ConsensusHash; !bytes.Equal(cH, tH) { 226 return nil, fmt.Errorf("params hash %X does not match trusted hash %X", 227 cH, tH) 228 } 229 230 return res, nil 231 } 232 233 func (c *Client) Health(ctx context.Context) (*ctypes.ResultHealth, error) { 234 return c.next.Health(ctx) 235 } 236 237 // BlockchainInfo calls rpcclient#BlockchainInfo and then verifies every header 238 // returned. 239 func (c *Client) BlockchainInfo(ctx context.Context, minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) { 240 res, err := c.next.BlockchainInfo(ctx, minHeight, maxHeight) 241 if err != nil { 242 return nil, err 243 } 244 245 // Validate res. 246 for i, meta := range res.BlockMetas { 247 if meta == nil { 248 return nil, fmt.Errorf("nil block meta %d", i) 249 } 250 if err := meta.ValidateBasic(); err != nil { 251 return nil, fmt.Errorf("invalid block meta %d: %w", i, err) 252 } 253 } 254 255 // Update the light client if we're behind. 256 if len(res.BlockMetas) > 0 { 257 lastHeight := res.BlockMetas[len(res.BlockMetas)-1].Header.Height 258 if _, err := c.updateLightClientIfNeededTo(ctx, &lastHeight); err != nil { 259 return nil, err 260 } 261 } 262 263 // Verify each of the BlockMetas. 264 for _, meta := range res.BlockMetas { 265 h, err := c.lc.TrustedLightBlock(meta.Header.Height) 266 if err != nil { 267 return nil, fmt.Errorf("trusted header %d: %w", meta.Header.Height, err) 268 } 269 if bmH, tH := meta.Header.Hash(), h.Hash(); !bytes.Equal(bmH, tH) { 270 return nil, fmt.Errorf("block meta header %X does not match with trusted header %X", 271 bmH, tH) 272 } 273 } 274 275 return res, nil 276 } 277 278 func (c *Client) Genesis(ctx context.Context) (*ctypes.ResultGenesis, error) { 279 return c.next.Genesis(ctx) 280 } 281 282 // Block calls rpcclient#Block and then verifies the result. 283 func (c *Client) Block(ctx context.Context, height *int64) (*ctypes.ResultBlock, error) { 284 res, err := c.next.Block(ctx, height) 285 if err != nil { 286 return nil, err 287 } 288 289 // Validate res. 290 if err := res.BlockID.ValidateBasic(); err != nil { 291 return nil, err 292 } 293 if err := res.Block.ValidateBasic(); err != nil { 294 return nil, err 295 } 296 if bmH, bH := res.BlockID.Hash, res.Block.Hash(); !bytes.Equal(bmH, bH) { 297 return nil, fmt.Errorf("blockID %X does not match with block %X", 298 bmH, bH) 299 } 300 301 // Update the light client if we're behind. 302 l, err := c.updateLightClientIfNeededTo(ctx, &res.Block.Height) 303 if err != nil { 304 return nil, err 305 } 306 307 // Verify block. 308 if bH, tH := res.Block.Hash(), l.Hash(); !bytes.Equal(bH, tH) { 309 return nil, fmt.Errorf("block header %X does not match with trusted header %X", 310 bH, tH) 311 } 312 313 return res, nil 314 } 315 316 // BlockByHash calls rpcclient#BlockByHash and then verifies the result. 317 func (c *Client) BlockByHash(ctx context.Context, hash []byte) (*ctypes.ResultBlock, error) { 318 res, err := c.next.BlockByHash(ctx, hash) 319 if err != nil { 320 return nil, err 321 } 322 323 // Validate res. 324 if err := res.BlockID.ValidateBasic(); err != nil { 325 return nil, err 326 } 327 if err := res.Block.ValidateBasic(); err != nil { 328 return nil, err 329 } 330 if bmH, bH := res.BlockID.Hash, res.Block.Hash(); !bytes.Equal(bmH, bH) { 331 return nil, fmt.Errorf("blockID %X does not match with block %X", 332 bmH, bH) 333 } 334 335 // Update the light client if we're behind. 336 l, err := c.updateLightClientIfNeededTo(ctx, &res.Block.Height) 337 if err != nil { 338 return nil, err 339 } 340 341 // Verify block. 342 if bH, tH := res.Block.Hash(), l.Hash(); !bytes.Equal(bH, tH) { 343 return nil, fmt.Errorf("block header %X does not match with trusted header %X", 344 bH, tH) 345 } 346 347 return res, nil 348 } 349 350 // BlockResults returns the block results for the given height. If no height is 351 // provided, the results of the block preceding the latest are returned. 352 func (c *Client) BlockResults(ctx context.Context, height *int64) (*ctypes.ResultBlockResults, error) { 353 var h int64 354 if height == nil { 355 res, err := c.next.Status(ctx) 356 if err != nil { 357 return nil, fmt.Errorf("can't get latest height: %w", err) 358 } 359 // Can't return the latest block results here because we won't be able to 360 // prove them. Return the results for the previous block instead. 361 h = res.SyncInfo.LatestBlockHeight - 1 362 } else { 363 h = *height 364 } 365 366 res, err := c.next.BlockResults(ctx, &h) 367 if err != nil { 368 return nil, err 369 } 370 371 // Validate res. 372 if res.Height <= 0 { 373 return nil, errNegOrZeroHeight 374 } 375 376 // Update the light client if we're behind. 377 nextHeight := h + 1 378 trustedBlock, err := c.updateLightClientIfNeededTo(ctx, &nextHeight) 379 if err != nil { 380 return nil, err 381 } 382 383 // proto-encode BeginBlock events 384 bbeBytes, err := proto.Marshal(&abci.ResponseBeginBlock{ 385 Events: res.BeginBlockEvents, 386 }) 387 if err != nil { 388 return nil, err 389 } 390 391 // Build a Merkle tree of proto-encoded DeliverTx results and get a hash. 392 results := types.NewResults(res.TxsResults) 393 394 // proto-encode EndBlock events. 395 ebeBytes, err := proto.Marshal(&abci.ResponseEndBlock{ 396 Events: res.EndBlockEvents, 397 }) 398 if err != nil { 399 return nil, err 400 } 401 402 // Build a Merkle tree out of the above 3 binary slices. 403 rH := merkle.HashFromByteSlices([][]byte{bbeBytes, results.Hash(), ebeBytes}) 404 405 // Verify block results. 406 if !bytes.Equal(rH, trustedBlock.LastResultsHash) { 407 return nil, fmt.Errorf("last results %X does not match with trusted last results %X", 408 rH, trustedBlock.LastResultsHash) 409 } 410 411 return res, nil 412 } 413 414 func (c *Client) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) { 415 // Update the light client if we're behind and retrieve the light block at the requested height 416 // or at the latest height if no height is provided. 417 l, err := c.updateLightClientIfNeededTo(ctx, height) 418 if err != nil { 419 return nil, err 420 } 421 422 return &ctypes.ResultCommit{ 423 SignedHeader: *l.SignedHeader, 424 CanonicalCommit: true, 425 }, nil 426 } 427 428 // Tx calls rpcclient#Tx method and then verifies the proof if such was 429 // requested. 430 func (c *Client) Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { 431 res, err := c.next.Tx(ctx, hash, prove) 432 if err != nil || !prove { 433 return res, err 434 } 435 436 // Validate res. 437 if res.Height <= 0 { 438 return nil, errNegOrZeroHeight 439 } 440 441 // Update the light client if we're behind. 442 l, err := c.updateLightClientIfNeededTo(ctx, &res.Height) 443 if err != nil { 444 return nil, err 445 } 446 447 // Validate the proof. 448 return res, res.Proof.Validate(l.DataHash) 449 } 450 451 func (c *Client) TxSearch(ctx context.Context, query string, prove bool, page, perPage *int, orderBy string) ( 452 *ctypes.ResultTxSearch, error) { 453 return c.next.TxSearch(ctx, query, prove, page, perPage, orderBy) 454 } 455 456 // Validators fetches and verifies validators. 457 func (c *Client) Validators(ctx context.Context, height *int64, pagePtr, perPagePtr *int) (*ctypes.ResultValidators, 458 error) { 459 // Update the light client if we're behind and retrieve the light block at the requested height 460 // or at the latest height if no height is provided. 461 l, err := c.updateLightClientIfNeededTo(ctx, height) 462 if err != nil { 463 return nil, err 464 } 465 466 totalCount := len(l.ValidatorSet.Validators) 467 perPage := validatePerPage(perPagePtr) 468 page, err := validatePage(pagePtr, perPage, totalCount) 469 if err != nil { 470 return nil, err 471 } 472 473 skipCount := validateSkipCount(page, perPage) 474 475 v := l.ValidatorSet.Validators[skipCount : skipCount+tmmath.MinInt(perPage, totalCount-skipCount)] 476 477 return &ctypes.ResultValidators{ 478 BlockHeight: l.Height, 479 Validators: v, 480 Count: len(v), 481 Total: totalCount}, nil 482 } 483 484 func (c *Client) BroadcastEvidence(ctx context.Context, ev types.Evidence) (*ctypes.ResultBroadcastEvidence, error) { 485 return c.next.BroadcastEvidence(ctx, ev) 486 } 487 488 func (c *Client) Subscribe(ctx context.Context, subscriber, query string, 489 outCapacity ...int) (out <-chan ctypes.ResultEvent, err error) { 490 return c.next.Subscribe(ctx, subscriber, query, outCapacity...) 491 } 492 493 func (c *Client) Unsubscribe(ctx context.Context, subscriber, query string) error { 494 return c.next.Unsubscribe(ctx, subscriber, query) 495 } 496 497 func (c *Client) UnsubscribeAll(ctx context.Context, subscriber string) error { 498 return c.next.UnsubscribeAll(ctx, subscriber) 499 } 500 501 func (c *Client) updateLightClientIfNeededTo(ctx context.Context, height *int64) (*types.LightBlock, error) { 502 var ( 503 l *types.LightBlock 504 err error 505 ) 506 if height == nil { 507 l, err = c.lc.Update(ctx, time.Now()) 508 } else { 509 l, err = c.lc.VerifyLightBlockAtHeight(ctx, *height, time.Now()) 510 } 511 if err != nil { 512 return nil, fmt.Errorf("failed to update light client to %d: %w", height, err) 513 } 514 return l, nil 515 } 516 517 func (c *Client) RegisterOpDecoder(typ string, dec merkle.OpDecoder) { 518 c.prt.RegisterOpDecoder(typ, dec) 519 } 520 521 // SubscribeWS subscribes for events using the given query and remote address as 522 // a subscriber, but does not verify responses (UNSAFE)! 523 // TODO: verify data 524 func (c *Client) SubscribeWS(ctx *rpctypes.Context, query string) (*ctypes.ResultSubscribe, error) { 525 out, err := c.next.Subscribe(context.Background(), ctx.RemoteAddr(), query) 526 if err != nil { 527 return nil, err 528 } 529 530 go func() { 531 for { 532 select { 533 case resultEvent := <-out: 534 // We should have a switch here that performs a validation 535 // depending on the event's type. 536 ctx.WSConn.TryWriteRPCResponse( 537 rpctypes.NewRPCSuccessResponse( 538 rpctypes.JSONRPCStringID(fmt.Sprintf("%v#event", ctx.JSONReq.ID)), 539 resultEvent, 540 )) 541 case <-c.Quit(): 542 return 543 } 544 } 545 }() 546 547 return &ctypes.ResultSubscribe{}, nil 548 } 549 550 // UnsubscribeWS calls original client's Unsubscribe using remote address as a 551 // subscriber. 552 func (c *Client) UnsubscribeWS(ctx *rpctypes.Context, query string) (*ctypes.ResultUnsubscribe, error) { 553 err := c.next.Unsubscribe(context.Background(), ctx.RemoteAddr(), query) 554 if err != nil { 555 return nil, err 556 } 557 return &ctypes.ResultUnsubscribe{}, nil 558 } 559 560 // UnsubscribeAllWS calls original client's UnsubscribeAll using remote address 561 // as a subscriber. 562 func (c *Client) UnsubscribeAllWS(ctx *rpctypes.Context) (*ctypes.ResultUnsubscribe, error) { 563 err := c.next.UnsubscribeAll(context.Background(), ctx.RemoteAddr()) 564 if err != nil { 565 return nil, err 566 } 567 return &ctypes.ResultUnsubscribe{}, nil 568 } 569 570 // XXX: Copied from rpc/core/env.go 571 const ( 572 // see README 573 defaultPerPage = 30 574 maxPerPage = 100 575 ) 576 577 func validatePage(pagePtr *int, perPage, totalCount int) (int, error) { 578 if perPage < 1 { 579 panic(fmt.Sprintf("zero or negative perPage: %d", perPage)) 580 } 581 582 if pagePtr == nil { // no page parameter 583 return 1, nil 584 } 585 586 pages := ((totalCount - 1) / perPage) + 1 587 if pages == 0 { 588 pages = 1 // one page (even if it's empty) 589 } 590 page := *pagePtr 591 if page <= 0 || page > pages { 592 return 1, fmt.Errorf("page should be within [1, %d] range, given %d", pages, page) 593 } 594 595 return page, nil 596 } 597 598 func validatePerPage(perPagePtr *int) int { 599 if perPagePtr == nil { // no per_page parameter 600 return defaultPerPage 601 } 602 603 perPage := *perPagePtr 604 if perPage < 1 { 605 return defaultPerPage 606 } else if perPage > maxPerPage { 607 return maxPerPage 608 } 609 return perPage 610 } 611 612 func validateSkipCount(page, perPage int) int { 613 skipCount := (page - 1) * perPage 614 if skipCount < 0 { 615 return 0 616 } 617 618 return skipCount 619 }