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.

236 lines
6.0 KiB

  1. package light_test
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/require"
  7. dbm "github.com/tendermint/tm-db"
  8. "github.com/tendermint/tendermint/abci/example/kvstore"
  9. "github.com/tendermint/tendermint/libs/log"
  10. "github.com/tendermint/tendermint/light"
  11. "github.com/tendermint/tendermint/light/provider"
  12. httpp "github.com/tendermint/tendermint/light/provider/http"
  13. dbs "github.com/tendermint/tendermint/light/store/db"
  14. rpctest "github.com/tendermint/tendermint/rpc/test"
  15. "github.com/tendermint/tendermint/types"
  16. )
  17. // NOTE: these are ports of the tests from example_test.go but
  18. // rewritten as more conventional tests.
  19. // Automatically getting new headers and verifying them.
  20. func TestClientIntegration_Update(t *testing.T) {
  21. t.Parallel()
  22. ctx, cancel := context.WithCancel(context.Background())
  23. defer cancel()
  24. conf, err := rpctest.CreateConfig(t, t.Name())
  25. require.NoError(t, err)
  26. logger := log.NewNopLogger()
  27. // Start a test application
  28. app := kvstore.NewApplication()
  29. _, closer, err := rpctest.StartTendermint(ctx, conf, app, rpctest.SuppressStdout)
  30. require.NoError(t, err)
  31. defer func() { require.NoError(t, closer(ctx)) }()
  32. // give Tendermint time to generate some blocks
  33. time.Sleep(5 * time.Second)
  34. dbDir := t.TempDir()
  35. chainID := conf.ChainID()
  36. primary, err := httpp.New(chainID, conf.RPC.ListenAddress)
  37. require.NoError(t, err)
  38. // give Tendermint time to generate some blocks
  39. block, err := waitForBlock(ctx, primary, 2)
  40. require.NoError(t, err)
  41. db, err := dbm.NewGoLevelDB("light-client-db", dbDir)
  42. require.NoError(t, err)
  43. c, err := light.NewClient(
  44. ctx,
  45. chainID,
  46. light.TrustOptions{
  47. Period: 504 * time.Hour, // 21 days
  48. Height: 2,
  49. Hash: block.Hash(),
  50. },
  51. primary,
  52. nil,
  53. dbs.New(db),
  54. light.Logger(logger),
  55. )
  56. require.NoError(t, err)
  57. defer func() { require.NoError(t, c.Cleanup()) }()
  58. // ensure Tendermint is at height 3 or higher
  59. _, err = waitForBlock(ctx, primary, 3)
  60. require.NoError(t, err)
  61. h, err := c.Update(ctx, time.Now())
  62. require.NoError(t, err)
  63. require.NotNil(t, h)
  64. require.True(t, h.Height > 2)
  65. }
  66. // Manually getting light blocks and verifying them.
  67. func TestClientIntegration_VerifyLightBlockAtHeight(t *testing.T) {
  68. t.Parallel()
  69. ctx, cancel := context.WithCancel(context.Background())
  70. defer cancel()
  71. conf, err := rpctest.CreateConfig(t, t.Name())
  72. require.NoError(t, err)
  73. logger := log.NewNopLogger()
  74. // Start a test application
  75. app := kvstore.NewApplication()
  76. _, closer, err := rpctest.StartTendermint(ctx, conf, app, rpctest.SuppressStdout)
  77. require.NoError(t, err)
  78. defer func() { require.NoError(t, closer(ctx)) }()
  79. dbDir := t.TempDir()
  80. chainID := conf.ChainID()
  81. primary, err := httpp.New(chainID, conf.RPC.ListenAddress)
  82. require.NoError(t, err)
  83. // give Tendermint time to generate some blocks
  84. block, err := waitForBlock(ctx, primary, 2)
  85. require.NoError(t, err)
  86. db, err := dbm.NewGoLevelDB("light-client-db", dbDir)
  87. require.NoError(t, err)
  88. c, err := light.NewClient(ctx,
  89. chainID,
  90. light.TrustOptions{
  91. Period: 504 * time.Hour, // 21 days
  92. Height: 2,
  93. Hash: block.Hash(),
  94. },
  95. primary,
  96. nil,
  97. dbs.New(db),
  98. light.Logger(logger),
  99. )
  100. require.NoError(t, err)
  101. defer func() { require.NoError(t, c.Cleanup()) }()
  102. // ensure Tendermint is at height 3 or higher
  103. _, err = waitForBlock(ctx, primary, 3)
  104. require.NoError(t, err)
  105. _, err = c.VerifyLightBlockAtHeight(ctx, 3, time.Now())
  106. require.NoError(t, err)
  107. h, err := c.TrustedLightBlock(3)
  108. require.NoError(t, err)
  109. require.EqualValues(t, 3, h.Height)
  110. }
  111. func waitForBlock(ctx context.Context, p provider.Provider, height int64) (*types.LightBlock, error) {
  112. for {
  113. block, err := p.LightBlock(ctx, height)
  114. switch err {
  115. case nil:
  116. return block, nil
  117. // node isn't running yet, wait 1 second and repeat
  118. case provider.ErrNoResponse, provider.ErrHeightTooHigh:
  119. timer := time.NewTimer(1 * time.Second)
  120. select {
  121. case <-ctx.Done():
  122. return nil, ctx.Err()
  123. case <-timer.C:
  124. }
  125. default:
  126. return nil, err
  127. }
  128. }
  129. }
  130. func TestClientStatusRPC(t *testing.T) {
  131. ctx, cancel := context.WithCancel(context.Background())
  132. defer cancel()
  133. conf, err := rpctest.CreateConfig(t, t.Name())
  134. require.NoError(t, err)
  135. // Start a test application
  136. app := kvstore.NewApplication()
  137. _, closer, err := rpctest.StartTendermint(ctx, conf, app, rpctest.SuppressStdout)
  138. require.NoError(t, err)
  139. defer func() { require.NoError(t, closer(ctx)) }()
  140. dbDir := t.TempDir()
  141. chainID := conf.ChainID()
  142. primary, err := httpp.New(chainID, conf.RPC.ListenAddress)
  143. require.NoError(t, err)
  144. // give Tendermint time to generate some blocks
  145. block, err := waitForBlock(ctx, primary, 2)
  146. require.NoError(t, err)
  147. db, err := dbm.NewGoLevelDB("light-client-db", dbDir)
  148. require.NoError(t, err)
  149. // In order to not create a full testnet we create the light client with no witnesses
  150. // and only verify the primary IP address.
  151. witnesses := []provider.Provider{}
  152. c, err := light.NewClient(ctx,
  153. chainID,
  154. light.TrustOptions{
  155. Period: 504 * time.Hour, // 21 days
  156. Height: 2,
  157. Hash: block.Hash(),
  158. },
  159. primary,
  160. witnesses,
  161. dbs.New(db),
  162. light.Logger(log.NewNopLogger()),
  163. )
  164. require.NoError(t, err)
  165. defer func() { require.NoError(t, c.Cleanup()) }()
  166. lightStatus := c.Status(ctx)
  167. // Verify primary IP
  168. require.True(t, lightStatus.PrimaryID == primary.ID())
  169. // Verify that number of peers is equal to number of witnesses (+ 1 if the primary is not a witness)
  170. require.Equal(t, len(witnesses)+1*primaryNotInWitnessList(witnesses, primary), lightStatus.NumPeers)
  171. // Verify that the last trusted hash returned matches the stored hash of the trusted
  172. // block at the last trusted height.
  173. blockAtTrustedHeight, err := c.TrustedLightBlock(lightStatus.LastTrustedHeight)
  174. require.NoError(t, err)
  175. require.EqualValues(t, lightStatus.LastTrustedHash, blockAtTrustedHeight.Hash())
  176. }
  177. // If the primary is not in the witness list, we will return 1
  178. // Otherwise, return 0
  179. func primaryNotInWitnessList(witnesses []provider.Provider, primary provider.Provider) int {
  180. for _, el := range witnesses {
  181. if el == primary {
  182. return 0
  183. }
  184. }
  185. return 1
  186. }