github.com/0xsequence/ethkit@v1.25.0/ethmonitor/ethmonitor_test.go (about) 1 package ethmonitor_test 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "os/exec" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/0xsequence/ethkit/ethmonitor" 13 "github.com/0xsequence/ethkit/ethrpc" 14 "github.com/0xsequence/ethkit/go-ethereum/common" 15 "github.com/0xsequence/ethkit/util" 16 "github.com/go-chi/httpvcr" 17 "github.com/stretchr/testify/assert" 18 ) 19 20 func TestMonitorBasic(t *testing.T) { 21 testConfig, err := util.ReadTestConfig("../ethkit-test.json") 22 if err != nil { 23 t.Error(err) 24 } 25 26 ethNodeURL := testConfig["GOERLI_URL"] 27 if ethNodeURL == "" { 28 ethNodeURL = "http://localhost:8545" 29 } 30 31 ctx := context.Background() 32 33 vcr := httpvcr.New("ethmonitor_goerli") 34 vcr.Start(ctx) 35 defer vcr.Stop() 36 37 vcr.URLRewriter = func(url string) string { 38 // rewrite the url to hide the API keys 39 return "http://goerli/" 40 } 41 42 monitorOptions := ethmonitor.DefaultOptions 43 if vcr.Mode() == httpvcr.ModeReplay { 44 // change options to run replay tests faster 45 monitorOptions.PollingInterval = 5 * time.Millisecond 46 } 47 48 provider, err := ethrpc.NewProvider(ethNodeURL) 49 assert.NoError(t, err) 50 51 monitor, err := ethmonitor.NewMonitor(provider, monitorOptions) 52 assert.NoError(t, err) 53 54 go func(t *testing.T) { 55 err := monitor.Run(context.Background()) 56 if err != nil { 57 panic(err) 58 } 59 }(t) 60 defer monitor.Stop() 61 62 sub := monitor.Subscribe("TestMonitorBasic") 63 defer sub.Unsubscribe() 64 65 subs := []ethmonitor.Subscription{} 66 go func() { 67 for i := 0; i < 10; i++ { 68 s := monitor.Subscribe(fmt.Sprintf("TestMonitorBasic/sub/%d", i)) 69 subs = append(subs, s) 70 } 71 72 time.Sleep(1 * time.Second) 73 for _, s := range subs { 74 s.Unsubscribe() 75 } 76 }() 77 78 go func() { 79 for { 80 select { 81 case blocks := <-sub.Blocks(): 82 _ = blocks 83 84 for _, b := range blocks { 85 fmt.Println("event:", b.Event, "block:", b.NumberU64(), b.Hash().Hex(), "parent:", b.ParentHash().Hex(), "# logs:", len(b.Logs)) 86 } 87 88 finalBlock := monitor.LatestFinalBlock(3) 89 if finalBlock != nil { 90 fmt.Println("finalized block #", finalBlock.NumberU64()) 91 } 92 93 case <-sub.Done(): 94 return 95 } 96 } 97 }() 98 99 // Wait for requests to complete 100 select { 101 case <-vcr.Done(): 102 break 103 case <-time.After(5 * time.Minute): // max amount of time to run the vcr recorder 104 break 105 } 106 monitor.Stop() 107 108 // Perform assertions 109 blocks := monitor.Chain().Blocks() 110 111 for _, b := range blocks { 112 _ = b 113 // fmt.Println("=> block", b.Hash()) 114 } 115 116 expectedBlockHashes := []string{ 117 "0x7f06fd3877f4d664c4525d33a0ada20287918dd0280b372ca859481bd09c81c4", 118 "0x0c4430bce8b4498657b88646827318c5d35cc52d3992d1fb97c28bcd69f0ff20", 119 "0x9e385c0a6a749f2b51b7ccf0412d02cb4e82e2600c56477b750fd580e5c98273", 120 "0x83fdf84b3cbfb4b0093025f9cc2db974e865d121b67dafafb70c2343837ccee2", 121 "0xdc482579c13aa25d0ae9ade680751ef8f80cf771b29ea9d3bb47af2bb474e251", 122 "0x2a45220ddbb622dad9107e84f3694b7fb03c52ced9e61e7293240595ffd5e620", 123 "0x4b45986f0409622d1fe90f476357135031aa5eee7d73586393c42524d20c1c12", 124 "0x377741ca51322567ab4d8f72226fd8d282bfc0c31cd506370430d71686c63641", 125 "0x0a096c3f639e40cdbf06dab7fca394310ddd689456aa0131edd94a495f706e68", 126 "0x56f1c94e1f3b466e4326f248e43d99d1bc8f55bc3147315a361dd4986fa5bd93", 127 "0x420d67c7494ab8ab878d4cbd66a451d60491794b54f3bb16bbbb76ac48f15072", 128 "0x8e00e1a3938f01b255e1cef3d8083730058745f0ae98f5cebc654d7ed6db3dbb", 129 "0xad24f03ed8bdfb9637232384e3257e076a47f3ac583492e8463a8d1a5fcdd31f", 130 "0x1147f217faa9a366f623d02453d099e60ddb30df36ec7ef9e80cc21adb43a730", 131 "0x253b4383d2e9afa7dbba30da47e44a691bd804114a10b37b803881fdc380da2a", 132 "0xb4cff922dd7cd5257acfdc433d672743dd1673030869da6f2278d4358803cf3c", 133 "0x5bc9ab2442688acb26b8e941660c62915418627452807367b9919011c4808b24", 134 "0x055ed7914285e38e30c69ae95bea80b49490a68d4057bd24b44b5444fcf34e70", 135 "0x9120c53b4d31cc0188e7e49b201df5ce091655491e37820f613cf7d44bb93bd7", 136 "0xdb1c79799e99a62c9dba44c7fb30e75f48da5f0ce67fdc4a2ecc08bf80bf52fb", 137 } 138 139 assert.True(t, len(expectedBlockHashes) <= len(blocks), "expected blocks returned part of retention") 140 141 for i := range expectedBlockHashes { 142 assert.Equal(t, expectedBlockHashes[i], blocks[i].Hash().Hex()) 143 } 144 145 assert.NotNil(t, monitor.GetBlock(common.HexToHash("0x2a45220ddbb622dad9107e84f3694b7fb03c52ced9e61e7293240595ffd5e620"))) 146 assert.Equal(t, common.HexToHash("0xdb1c79799e99a62c9dba44c7fb30e75f48da5f0ce67fdc4a2ecc08bf80bf52fb"), monitor.LatestBlock().Hash()) 147 148 // only subscriber left is the main one 149 assert.True(t, monitor.NumSubscribers() == 1) 150 } 151 152 func GetIp(index uint) string { 153 output, err := exec.Command("yarn", "--silent", "--cwd", "../tools/reorgme", "chain:ip", "0").CombinedOutput() 154 155 if err != nil { 156 os.Stderr.WriteString(err.Error()) 157 } 158 159 return strings.Replace(string(output), "\n", "", 1) 160 } 161 162 func WaitBlock(ctx context.Context, provider *ethrpc.Provider) error { 163 var lastBlock = uint64(0) 164 165 fmt.Println("Waiting a block") 166 167 for { 168 block, err := provider.BlockNumber(ctx) 169 if err != nil { 170 return err 171 } 172 173 if lastBlock == 0 { 174 lastBlock = block 175 } 176 177 if block != lastBlock { 178 return nil 179 } 180 } 181 } 182 183 func Fork(index uint) string { 184 fmt.Println("Forking...") 185 output, err := exec.Command("yarn", "--silent", "--cwd", "../tools/reorgme", "chain:fork").CombinedOutput() 186 187 if err != nil { 188 os.Stderr.WriteString(err.Error()) 189 } 190 191 fmt.Println("Forked!") 192 193 return string(output) 194 } 195 196 func Join(index uint) string { 197 fmt.Println("Joining...") 198 output, err := exec.Command("yarn", "--silent", "--cwd", "../tools/reorgme", "chain:join").CombinedOutput() 199 200 if err != nil { 201 os.Stderr.WriteString(err.Error()) 202 } 203 204 fmt.Println("Joined!") 205 206 return string(output) 207 } 208 209 func TestMonitorWithReorgme(t *testing.T) { 210 if strings.ToLower(os.Getenv("REORGME")) != "true" { 211 t.Logf("REORGME is not enabled, skipping this test case.") 212 return 213 } 214 215 ip := GetIp(0) 216 217 provider, err := ethrpc.NewProvider("http://" + ip + ":8545/") 218 assert.NoError(t, err) 219 220 monitorOptions := ethmonitor.DefaultOptions 221 monitorOptions.PollingInterval = 5 * time.Millisecond 222 223 monitor, err := ethmonitor.NewMonitor(provider, monitorOptions) 224 assert.NoError(t, err) 225 226 go func(t *testing.T) { 227 err := monitor.Run(context.Background()) 228 if err != nil { 229 panic(err) 230 } 231 }(t) 232 defer monitor.Stop() 233 234 sub := monitor.Subscribe("TestMonitorWithReorgme") 235 defer sub.Unsubscribe() 236 237 events := make([]*ethmonitor.Block, 0) 238 239 go func() { 240 for { 241 select { 242 case blocks := <-sub.Blocks(): 243 _ = blocks 244 for _, b := range blocks { 245 events = append(events, b) 246 fmt.Println("event:", b.Event, "block:", b.NumberU64(), b.Hash().Hex(), "parent:", b.ParentHash().Hex(), "# logs:", len(b.Logs)) 247 } 248 case <-sub.Done(): 249 return 250 } 251 } 252 }() 253 254 Fork(0) 255 events = make([]*ethmonitor.Block, 0) 256 257 WaitBlock(context.Background(), provider) 258 WaitBlock(context.Background(), provider) 259 260 time.Sleep(2 * time.Second) 261 262 for _, b := range events { 263 assert.Equal(t, b.Event, ethmonitor.Added) 264 } 265 266 revertedEvents := events 267 events = make([]*ethmonitor.Block, 0) 268 269 Join(0) 270 271 // Wait for reorg 272 WaitBlock(context.Background(), provider) 273 WaitBlock(context.Background(), provider) 274 275 time.Sleep(2 * time.Second) 276 277 offset := 0 278 for _, e := range events { 279 if e.Block.Hash() == revertedEvents[len(revertedEvents)-1].Hash() { 280 break 281 } 282 283 offset++ 284 } 285 286 for i, b := range revertedEvents { 287 ri := len(revertedEvents) - 1 - i + offset 288 rb := events[ri] 289 290 // Should revert last blocks 291 assert.Equal(t, rb.Block.Number(), b.Block.Number()) 292 assert.Equal(t, rb.Block.Hash(), b.Block.Hash()) 293 assert.Equal(t, b.Event, ethmonitor.Removed) 294 } 295 296 monitor.Stop() 297 }