header_traversal_test.go 4.11 KB
Newer Older
1 2 3 4 5 6 7
package node

import (
	"math/big"
	"testing"

	"github.com/stretchr/testify/mock"
8
	"github.com/stretchr/testify/require"
9 10 11 12

	"github.com/ethereum/go-ethereum/core/types"
)

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
// make a set of headers which chain correctly
func makeHeaders(numHeaders uint64, prevHeader *types.Header) []*types.Header {
	headers := make([]*types.Header, numHeaders)
	for i := range headers {
		if i == 0 {
			if prevHeader == nil {
				// genesis
				headers[i] = &types.Header{Number: big.NewInt(0)}
			} else {
				// chain onto the previous header
				headers[i] = &types.Header{Number: big.NewInt(prevHeader.Number.Int64() + 1)}
				headers[i].ParentHash = prevHeader.Hash()
			}
		} else {
			prevHeader = headers[i-1]
			headers[i] = &types.Header{Number: big.NewInt(prevHeader.Number.Int64() + 1)}
			headers[i].ParentHash = prevHeader.Hash()
		}
	}

	return headers
34 35
}

36
func TestHeaderTraversalNextFinalizedHeadersNoOp(t *testing.T) {
37
	client := new(MockEthClient)
38

39 40 41
	// start from block 10 as the latest fetched block
	lastHeader := &types.Header{Number: big.NewInt(10)}
	headerTraversal := NewHeaderTraversal(client, lastHeader)
42

43
	// no new headers when matched with head
44 45
	client.On("FinalizedBlockHeight").Return(big.NewInt(10), nil)
	headers, err := headerTraversal.NextFinalizedHeaders(100)
46 47
	require.NoError(t, err)
	require.Empty(t, headers)
48 49
}

50
func TestHeaderTraversalNextFinalizedHeadersCursored(t *testing.T) {
51 52
	client := new(MockEthClient)

53
	// start from genesis
54
	headerTraversal := NewHeaderTraversal(client, nil)
55

56 57 58 59
	// blocks [0..4]
	headers := makeHeaders(5, nil)
	client.On("FinalizedBlockHeight").Return(big.NewInt(4), nil).Times(1) // Times so that we can override next
	client.On("BlockHeadersByRange", mock.MatchedBy(bigIntMatcher(0)), mock.MatchedBy(bigIntMatcher(4))).Return(headers, nil)
60
	headers, err := headerTraversal.NextFinalizedHeaders(5)
61 62
	require.NoError(t, err)
	require.Len(t, headers, 5)
63

64 65 66 67
	// blocks [5..9]
	headers = makeHeaders(5, headers[len(headers)-1])
	client.On("FinalizedBlockHeight").Return(big.NewInt(9), nil)
	client.On("BlockHeadersByRange", mock.MatchedBy(bigIntMatcher(5)), mock.MatchedBy(bigIntMatcher(9))).Return(headers, nil)
68
	headers, err = headerTraversal.NextFinalizedHeaders(5)
69 70
	require.NoError(t, err)
	require.Len(t, headers, 5)
71 72
}

73
func TestHeaderTraversalNextFinalizedHeadersMaxSize(t *testing.T) {
74
	client := new(MockEthClient)
75 76

	// start from genesis
77
	headerTraversal := NewHeaderTraversal(client, nil)
78

79 80
	// 100 "available" headers
	client.On("FinalizedBlockHeight").Return(big.NewInt(100), nil)
81

82 83 84 85
	// clamped by the supplied size
	headers := makeHeaders(5, nil)
	client.On("BlockHeadersByRange", mock.MatchedBy(bigIntMatcher(0)), mock.MatchedBy(bigIntMatcher(4))).Return(headers, nil)
	headers, err := headerTraversal.NextFinalizedHeaders(5)
86 87
	require.NoError(t, err)
	require.Len(t, headers, 5)
88

89 90 91 92
	// clamped by the supplied size. FinalizedHeight == 100
	headers = makeHeaders(10, headers[len(headers)-1])
	client.On("BlockHeadersByRange", mock.MatchedBy(bigIntMatcher(5)), mock.MatchedBy(bigIntMatcher(14))).Return(headers, nil)
	headers, err = headerTraversal.NextFinalizedHeaders(10)
93 94
	require.NoError(t, err)
	require.Len(t, headers, 10)
95 96
}

97
func TestHeaderTraversalMismatchedProviderStateError(t *testing.T) {
98 99 100
	client := new(MockEthClient)

	// start from genesis
101
	headerTraversal := NewHeaderTraversal(client, nil)
102 103 104 105 106

	// blocks [0..4]
	headers := makeHeaders(5, nil)
	client.On("FinalizedBlockHeight").Return(big.NewInt(4), nil).Times(1) // Times so that we can override next
	client.On("BlockHeadersByRange", mock.MatchedBy(bigIntMatcher(0)), mock.MatchedBy(bigIntMatcher(4))).Return(headers, nil)
107
	headers, err := headerTraversal.NextFinalizedHeaders(5)
108 109
	require.NoError(t, err)
	require.Len(t, headers, 5)
110 111 112 113 114

	// blocks [5..9]. Next batch is not chained correctly (starts again from genesis)
	headers = makeHeaders(5, nil)
	client.On("FinalizedBlockHeight").Return(big.NewInt(9), nil)
	client.On("BlockHeadersByRange", mock.MatchedBy(bigIntMatcher(5)), mock.MatchedBy(bigIntMatcher(9))).Return(headers, nil)
115
	headers, err = headerTraversal.NextFinalizedHeaders(5)
116 117
	require.Nil(t, headers)
	require.Equal(t, ErrHeaderTraversalAndProviderMismatchedState, err)
118
}