You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
5.5 KiB

  1. package proxy
  2. import (
  3. "github.com/tendermint/go-wire/data"
  4. "github.com/tendermint/tendermint/lite"
  5. certclient "github.com/tendermint/tendermint/lite/client"
  6. rpcclient "github.com/tendermint/tendermint/rpc/client"
  7. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  8. )
  9. var _ rpcclient.Client = Wrapper{}
  10. // Wrapper wraps a rpcclient with a Certifier and double-checks any input that is
  11. // provable before passing it along. Allows you to make any rpcclient fully secure.
  12. type Wrapper struct {
  13. rpcclient.Client
  14. cert *lite.Inquiring
  15. }
  16. // SecureClient uses a given certifier to wrap an connection to an untrusted
  17. // host and return a cryptographically secure rpc client.
  18. //
  19. // If it is wrapping an HTTP rpcclient, it will also wrap the websocket interface
  20. func SecureClient(c rpcclient.Client, cert *lite.Inquiring) Wrapper {
  21. wrap := Wrapper{c, cert}
  22. // TODO: no longer possible as no more such interface exposed....
  23. // if we wrap http client, then we can swap out the event switch to filter
  24. // if hc, ok := c.(*rpcclient.HTTP); ok {
  25. // evt := hc.WSEvents.EventSwitch
  26. // hc.WSEvents.EventSwitch = WrappedSwitch{evt, wrap}
  27. // }
  28. return wrap
  29. }
  30. // ABCIQueryWithOptions exposes all options for the ABCI query and verifies the returned proof
  31. func (w Wrapper) ABCIQueryWithOptions(path string, data data.Bytes, opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
  32. res, _, err := GetWithProofOptions(path, data, opts, w.Client, w.cert)
  33. return res, err
  34. }
  35. // ABCIQuery uses default options for the ABCI query and verifies the returned proof
  36. func (w Wrapper) ABCIQuery(path string, data data.Bytes) (*ctypes.ResultABCIQuery, error) {
  37. return w.ABCIQueryWithOptions(path, data, rpcclient.DefaultABCIQueryOptions)
  38. }
  39. // Tx queries for a given tx and verifies the proof if it was requested
  40. func (w Wrapper) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
  41. res, err := w.Client.Tx(hash, prove)
  42. if !prove || err != nil {
  43. return res, err
  44. }
  45. h := int64(res.Height)
  46. check, err := GetCertifiedCommit(h, w.Client, w.cert)
  47. if err != nil {
  48. return res, err
  49. }
  50. err = res.Proof.Validate(check.Header.DataHash)
  51. return res, err
  52. }
  53. // BlockchainInfo requests a list of headers and verifies them all...
  54. // Rather expensive.
  55. //
  56. // TODO: optimize this if used for anything needing performance
  57. func (w Wrapper) BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
  58. r, err := w.Client.BlockchainInfo(minHeight, maxHeight)
  59. if err != nil {
  60. return nil, err
  61. }
  62. // go and verify every blockmeta in the result....
  63. for _, meta := range r.BlockMetas {
  64. // get a checkpoint to verify from
  65. c, err := w.Commit(&meta.Header.Height)
  66. if err != nil {
  67. return nil, err
  68. }
  69. check := certclient.CommitFromResult(c)
  70. err = ValidateBlockMeta(meta, check)
  71. if err != nil {
  72. return nil, err
  73. }
  74. }
  75. return r, nil
  76. }
  77. // Block returns an entire block and verifies all signatures
  78. func (w Wrapper) Block(height *int64) (*ctypes.ResultBlock, error) {
  79. r, err := w.Client.Block(height)
  80. if err != nil {
  81. return nil, err
  82. }
  83. // get a checkpoint to verify from
  84. c, err := w.Commit(height)
  85. if err != nil {
  86. return nil, err
  87. }
  88. check := certclient.CommitFromResult(c)
  89. // now verify
  90. err = ValidateBlockMeta(r.BlockMeta, check)
  91. if err != nil {
  92. return nil, err
  93. }
  94. err = ValidateBlock(r.Block, check)
  95. if err != nil {
  96. return nil, err
  97. }
  98. return r, nil
  99. }
  100. // Commit downloads the Commit and certifies it with the lite.
  101. //
  102. // This is the foundation for all other verification in this module
  103. func (w Wrapper) Commit(height *int64) (*ctypes.ResultCommit, error) {
  104. rpcclient.WaitForHeight(w.Client, *height, nil)
  105. r, err := w.Client.Commit(height)
  106. // if we got it, then certify it
  107. if err == nil {
  108. check := certclient.CommitFromResult(r)
  109. err = w.cert.Certify(check)
  110. }
  111. return r, err
  112. }
  113. // // WrappedSwitch creates a websocket connection that auto-verifies any info
  114. // // coming through before passing it along.
  115. // //
  116. // // Since the verification takes 1-2 rpc calls, this is obviously only for
  117. // // relatively low-throughput situations that can tolerate a bit extra latency
  118. // type WrappedSwitch struct {
  119. // types.EventSwitch
  120. // client rpcclient.Client
  121. // }
  122. // // FireEvent verifies any block or header returned from the eventswitch
  123. // func (s WrappedSwitch) FireEvent(event string, data events.EventData) {
  124. // tm, ok := data.(types.TMEventData)
  125. // if !ok {
  126. // fmt.Printf("bad type %#v\n", data)
  127. // return
  128. // }
  129. // // check to validate it if possible, and drop if not valid
  130. // switch t := tm.Unwrap().(type) {
  131. // case types.EventDataNewBlockHeader:
  132. // err := verifyHeader(s.client, t.Header)
  133. // if err != nil {
  134. // fmt.Printf("Invalid header: %#v\n", err)
  135. // return
  136. // }
  137. // case types.EventDataNewBlock:
  138. // err := verifyBlock(s.client, t.Block)
  139. // if err != nil {
  140. // fmt.Printf("Invalid block: %#v\n", err)
  141. // return
  142. // }
  143. // // TODO: can we verify tx as well? anything else
  144. // }
  145. // // looks good, we fire it
  146. // s.EventSwitch.FireEvent(event, data)
  147. // }
  148. // func verifyHeader(c rpcclient.Client, head *types.Header) error {
  149. // // get a checkpoint to verify from
  150. // commit, err := c.Commit(&head.Height)
  151. // if err != nil {
  152. // return err
  153. // }
  154. // check := certclient.CommitFromResult(commit)
  155. // return ValidateHeader(head, check)
  156. // }
  157. //
  158. // func verifyBlock(c rpcclient.Client, block *types.Block) error {
  159. // // get a checkpoint to verify from
  160. // commit, err := c.Commit(&block.Height)
  161. // if err != nil {
  162. // return err
  163. // }
  164. // check := certclient.CommitFromResult(commit)
  165. // return ValidateBlock(block, check)
  166. // }