-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathwhats_on_chain_spec.rb
More file actions
137 lines (105 loc) · 4.85 KB
/
whats_on_chain_spec.rb
File metadata and controls
137 lines (105 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# frozen_string_literal: true
RSpec.describe BSV::Transaction::ChainTrackers::WhatsOnChain do
let(:http_client) { instance_double(Net::HTTP) }
let(:tracker) { described_class.new(http_client: http_client) }
let(:merkle_root) { '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b' }
let(:header_json) do
{
'hash' => '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f',
'confirmations' => 800_000,
'size' => 285,
'height' => 0,
'version' => 1,
'merkleroot' => merkle_root,
'tx' => [],
'time' => 1_231_006_505,
'nonce' => 2_083_236_893,
'bits' => '1d00ffff',
'previousblockhash' => '0000000000000000000000000000000000000000000000000000000000000000'
}.to_json
end
def mock_response(code, body)
instance_double(Net::HTTPResponse, code: code.to_s, body: body)
end
describe '#valid_root_for_height?' do
it 'returns true when root matches' do
allow(http_client).to receive(:request).and_return(mock_response(200, header_json))
expect(tracker.valid_root_for_height?(merkle_root, 0)).to be true
end
it 'returns true with case-insensitive comparison' do
allow(http_client).to receive(:request).and_return(mock_response(200, header_json))
expect(tracker.valid_root_for_height?(merkle_root.upcase, 0)).to be true
end
it 'returns false when root does not match' do
allow(http_client).to receive(:request).and_return(mock_response(200, header_json))
expect(tracker.valid_root_for_height?('0000' * 16, 0)).to be false
end
it 'returns false for 404 (block not found)' do
allow(http_client).to receive(:request).and_return(mock_response(404, 'Not Found'))
expect(tracker.valid_root_for_height?(merkle_root, 999_999_999)).to be false
end
it 'raises ChainProviderError for server errors' do
allow(http_client).to receive(:request).and_return(mock_response(500, 'Internal Server Error'))
expect { tracker.valid_root_for_height?(merkle_root, 0) }
.to raise_error(BSV::Network::ChainProviderError) { |e| expect(e.status_code).to eq(500) }
end
it 'sends request to correct URL for mainnet' do
allow(http_client).to receive(:request).and_return(mock_response(200, header_json))
tracker.valid_root_for_height?(merkle_root, 100)
expect(http_client).to have_received(:request) do |uri, _req|
expect(uri.to_s).to eq('https://api.whatsonchain.com/v1/bsv/main/block/100/header')
end
end
it 'sends API key in Authorization header when provided' do
keyed_tracker = described_class.new(api_key: 'my-key', http_client: http_client)
allow(http_client).to receive(:request).and_return(mock_response(200, header_json))
keyed_tracker.valid_root_for_height?(merkle_root, 0)
expect(http_client).to have_received(:request) do |_uri, req|
expect(req['Authorization']).to eq('my-key')
end
end
end
describe '#current_height' do
let(:chain_info_json) do
{ 'chain' => 'main', 'blocks' => 800_123, 'bestblockhash' => 'abc' }.to_json
end
it 'returns the current block height' do
allow(http_client).to receive(:request).and_return(mock_response(200, chain_info_json))
expect(tracker.current_height).to eq(800_123)
end
it 'raises ChainProviderError on failure' do
allow(http_client).to receive(:request).and_return(mock_response(503, 'Unavailable'))
expect { tracker.current_height }
.to raise_error(BSV::Network::ChainProviderError) { |e| expect(e.status_code).to eq(503) }
end
end
describe 'network configuration' do
it 'defaults to mainnet' do
allow(http_client).to receive(:request).and_return(mock_response(200, header_json))
tracker.valid_root_for_height?(merkle_root, 0)
expect(http_client).to have_received(:request) do |uri, _req|
expect(uri.path).to include('/bsv/main/')
end
end
it 'supports testnet' do
test_tracker = described_class.new(network: :test, http_client: http_client)
allow(http_client).to receive(:request).and_return(mock_response(200, header_json))
test_tracker.valid_root_for_height?(merkle_root, 0)
expect(http_client).to have_received(:request) do |uri, _req|
expect(uri.path).to include('/bsv/test/')
end
end
it 'supports stn' do
stn_tracker = described_class.new(network: :stn, http_client: http_client)
allow(http_client).to receive(:request).and_return(mock_response(200, header_json))
stn_tracker.valid_root_for_height?(merkle_root, 0)
expect(http_client).to have_received(:request) do |uri, _req|
expect(uri.path).to include('/bsv/stn/')
end
end
it 'raises ArgumentError for unknown network' do
expect { described_class.new(network: :invalid) }
.to raise_error(ArgumentError, /unknown network/)
end
end
end