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