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