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