|
7 | 7 | "encoding/binary" |
8 | 8 | "encoding/hex" |
9 | 9 | "encoding/json" |
| 10 | + "errors" |
10 | 11 | "fmt" |
11 | 12 | "os" |
12 | 13 | "testing" |
@@ -1659,3 +1660,100 @@ func TestEthEstimateGas(t *testing.T) { |
1659 | 1660 | }) |
1660 | 1661 | } |
1661 | 1662 | } |
| 1663 | + |
| 1664 | +func TestEthNullRoundHandling(t *testing.T) { |
| 1665 | + blockTime := 100 * time.Millisecond |
| 1666 | + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) |
| 1667 | + |
| 1668 | + bms := ens.InterconnectAll().BeginMining(blockTime) |
| 1669 | + |
| 1670 | + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) |
| 1671 | + defer cancel() |
| 1672 | + |
| 1673 | + bms[0].InjectNulls(10) |
| 1674 | + |
| 1675 | + tctx, cancel := context.WithTimeout(ctx, 30*time.Second) |
| 1676 | + defer cancel() |
| 1677 | + ch, err := client.ChainNotify(tctx) |
| 1678 | + require.NoError(t, err) |
| 1679 | + <-ch |
| 1680 | + hc := <-ch |
| 1681 | + require.Equal(t, store.HCApply, hc[0].Type) |
| 1682 | + |
| 1683 | + afterNullHeight := hc[0].Val.Height() |
| 1684 | + |
| 1685 | + nullHeight := afterNullHeight - 1 |
| 1686 | + for nullHeight > 0 { |
| 1687 | + ts, err := client.ChainGetTipSetByHeight(ctx, nullHeight, types.EmptyTSK) |
| 1688 | + require.NoError(t, err) |
| 1689 | + if ts.Height() == nullHeight { |
| 1690 | + nullHeight-- |
| 1691 | + } else { |
| 1692 | + break |
| 1693 | + } |
| 1694 | + } |
| 1695 | + |
| 1696 | + nullBlockHex := fmt.Sprintf("0x%x", nullHeight) |
| 1697 | + |
| 1698 | + testCases := []struct { |
| 1699 | + name string |
| 1700 | + testFunc func() error |
| 1701 | + }{ |
| 1702 | + { |
| 1703 | + name: "EthGetBlockByNumber", |
| 1704 | + testFunc: func() error { |
| 1705 | + _, err := client.EthGetBlockByNumber(ctx, nullBlockHex, true) |
| 1706 | + if err == nil { |
| 1707 | + return errors.New("expected error for null round") |
| 1708 | + } |
| 1709 | + return err |
| 1710 | + }, |
| 1711 | + }, |
| 1712 | + { |
| 1713 | + name: "EthFeeHistory", |
| 1714 | + testFunc: func() error { |
| 1715 | + params, err := json.Marshal([]interface{}{1, nullBlockHex}) |
| 1716 | + if err != nil { |
| 1717 | + return err |
| 1718 | + } |
| 1719 | + _, err = client.EthFeeHistory(ctx, params) |
| 1720 | + return err |
| 1721 | + }, |
| 1722 | + }, |
| 1723 | + { |
| 1724 | + name: "EthTraceBlock", |
| 1725 | + testFunc: func() error { |
| 1726 | + _, err := client.EthTraceBlock(ctx, nullBlockHex) |
| 1727 | + return err |
| 1728 | + }, |
| 1729 | + }, |
| 1730 | + { |
| 1731 | + name: "EthTraceReplayBlockTransactions", |
| 1732 | + testFunc: func() error { |
| 1733 | + _, err := client.EthTraceReplayBlockTransactions(ctx, nullBlockHex, []string{"trace"}) |
| 1734 | + return err |
| 1735 | + }, |
| 1736 | + }, |
| 1737 | + } |
| 1738 | + |
| 1739 | + for _, tc := range testCases { |
| 1740 | + t.Run(tc.name, func(t *testing.T) { |
| 1741 | + err := tc.testFunc() |
| 1742 | + t.Logf("error: %v", err) |
| 1743 | + require.Error(t, err) |
| 1744 | + |
| 1745 | + // Test errors.Is |
| 1746 | + require.True(t, errors.Is(err, new(api.ErrNullRound)), |
| 1747 | + "error should be or wrap ErrNullRound") |
| 1748 | + |
| 1749 | + // Test errors.As and verify message |
| 1750 | + var nullRoundErr *api.ErrNullRound |
| 1751 | + require.True(t, errors.As(err, &nullRoundErr), |
| 1752 | + "error should be convertible to ErrNullRound") |
| 1753 | + |
| 1754 | + expectedMsg := fmt.Sprintf("block number %s was a null round", nullBlockHex) |
| 1755 | + require.Equal(t, expectedMsg, nullRoundErr.Error()) |
| 1756 | + require.Equal(t, nullHeight, nullRoundErr.Epoch) |
| 1757 | + }) |
| 1758 | + } |
| 1759 | +} |
0 commit comments