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

	return headers
33 34
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	// 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)
113
	client.On("BlockHeadersByRange", mock.MatchedBy(BigIntMatcher(5)), mock.MatchedBy(BigIntMatcher(9))).Return(headers, nil)
114
	headers, err = headerTraversal.NextFinalizedHeaders(5)
115 116
	require.Nil(t, headers)
	require.Equal(t, ErrHeaderTraversalAndProviderMismatchedState, err)
117
}