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