parent
2b7610f289
commit
7c0cf2c2c4
@ -0,0 +1,38 @@ |
||||
defmodule Explorer.SkippedBlocks do |
||||
alias Explorer.Fetcher |
||||
alias Explorer.Block |
||||
alias Explorer.Repo |
||||
alias Ecto.Adapters.SQL |
||||
import Ecto.Query |
||||
|
||||
@moduledoc false |
||||
|
||||
@query """ |
||||
SELECT missing_numbers.number AS missing_number |
||||
FROM generate_series(1, $1) missing_numbers(number) |
||||
LEFT OUTER JOIN blocks ON (blocks.number = missing_numbers.number) |
||||
WHERE blocks.id IS NULL; |
||||
""" |
||||
|
||||
@dialyzer {:nowarn_function, fetch: 0} |
||||
def fetch do |
||||
get_skipped_blocks() |
||||
|> Enum.map(&Integer.to_string/1) |
||||
|> Enum.map(&Fetcher.fetch/1) |
||||
end |
||||
|
||||
def get_skipped_blocks do |
||||
last_block_number = get_last_block_number() |
||||
SQL.query!(Repo, @query, [last_block_number]).rows |
||||
|> Enum.map(&List.first/1) |
||||
end |
||||
|
||||
def get_last_block_number do |
||||
block = Block |
||||
|> order_by(desc: :number) |
||||
|> limit(1) |
||||
|> Repo.all |
||||
|> List.first || %{number: 0} |
||||
block.number |
||||
end |
||||
end |
@ -0,0 +1,12 @@ |
||||
defmodule Mix.Tasks.Backfill do |
||||
use Mix.Task |
||||
alias Explorer.SkippedBlocks |
||||
|
||||
@shortdoc "Backfill blocks from the chain." |
||||
@moduledoc false |
||||
|
||||
def run(_) do |
||||
Mix.Task.run("app.start") |
||||
SkippedBlocks.fetch() |
||||
end |
||||
end |
@ -0,0 +1,53 @@ |
||||
defmodule Explorer.SkippedBlocksTest do |
||||
use Explorer.DataCase |
||||
|
||||
alias Explorer.Block |
||||
alias Explorer.Repo |
||||
alias Explorer.SkippedBlocks |
||||
|
||||
describe "fetch/0" do |
||||
test "inserts a missing block into the database" do |
||||
insert(:block, %{number: 2}) |
||||
use_cassette "skipped_block_fetch" do |
||||
SkippedBlocks.fetch() |
||||
|
||||
blocks = Block |> order_by(asc: :number) |> Repo.all |> Enum.map(fn(block) -> block.number end) |
||||
|
||||
assert blocks == [1, 2] |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe "get_skipped_blocks/0 when there are no blocks" do |
||||
test "returns no blocks" do |
||||
assert SkippedBlocks.get_skipped_blocks() == [] |
||||
end |
||||
end |
||||
|
||||
describe "get_skipped_blocks/0 when there are no skipped blocks" do |
||||
test "returns no blocks" do |
||||
insert(:block, %{number: 1}) |
||||
assert SkippedBlocks.get_skipped_blocks() == [] |
||||
end |
||||
end |
||||
|
||||
describe "get_skipped_blocks/0 when a block has been skipped" do |
||||
test "returns no blocks" do |
||||
insert(:block, %{number: 2}) |
||||
assert SkippedBlocks.get_skipped_blocks() == [1] |
||||
end |
||||
end |
||||
|
||||
describe "get_last_block_number/0 when there are no blocks" do |
||||
test "returns zero" do |
||||
assert SkippedBlocks.get_last_block_number() == 0 |
||||
end |
||||
end |
||||
|
||||
describe "get_last_block_number/0 when there is a block" do |
||||
test "returns the number of the block" do |
||||
insert(:block, %{number: 1}) |
||||
assert SkippedBlocks.get_last_block_number() == 1 |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,21 @@ |
||||
defmodule Scrape.Backfill do |
||||
use Explorer.DataCase |
||||
alias Explorer.Block |
||||
alias Explorer.Repo |
||||
|
||||
test "backfills previous blocks" do |
||||
insert(:block, %{number: 2}) |
||||
|
||||
use_cassette "backfill" do |
||||
Mix.Tasks.Backfill.run([]) |
||||
|
||||
last_block = Block |
||||
|> order_by(asc: :number) |
||||
|> limit(1) |
||||
|> Repo.all |
||||
|> List.first |
||||
|
||||
assert last_block.number == 1 |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,30 @@ |
||||
[ |
||||
{ |
||||
"request": { |
||||
"body": "{\"params\":[\"1\",true],\"method\":\"eth_getBlockByNumber\",\"jsonrpc\":\"2.0\",\"id\":2}", |
||||
"headers": { |
||||
"Content-Type": "application/json" |
||||
}, |
||||
"method": "post", |
||||
"options": [], |
||||
"request_body": "", |
||||
"url": "https://sokol.poa.network:443" |
||||
}, |
||||
"response": { |
||||
"binary": false, |
||||
"body": "{\"jsonrpc\":\"2.0\",\"result\":{\"author\":\"0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca\",\"difficulty\":\"0xffffffffffffffffffffffffedf58e45\",\"extraData\":\"0xd5830108048650617269747986312e32322e31826c69\",\"gasLimit\":\"0x66556d\",\"gasUsed\":\"0x0\",\"hash\":\"0x52c867bc0a91e573dc39300143c3bead7408d09d45bdb686749f02684ece72f3\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca\",\"number\":\"0x1\",\"parentHash\":\"0x5b28c1bfd3a15230c9a46b399cd0f9a6920d432e85381cc6a140b06e8410112f\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sealFields\":[\"0x84120a71ba\",\"0xb8417a5887662f09ac4673af5850d28f3ad6550407b9c814ef563a13320f881b55ef03754f48f2dde027ad4a5abcabcc42780d9ebfc645f183e5252507d6a25bc2ec01\"],\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"signature\":\"7a5887662f09ac4673af5850d28f3ad6550407b9c814ef563a13320f881b55ef03754f48f2dde027ad4a5abcabcc42780d9ebfc645f183e5252507d6a25bc2ec01\",\"size\":\"0x240\",\"stateRoot\":\"0xc196ad59d867542ef20b29df5f418d07dc7234f4bc3d25260526620b7958a8fb\",\"step\":\"302674362\",\"timestamp\":\"0x5a3438a2\",\"totalDifficulty\":\"0xffffffffffffffffffffffffedf78e45\",\"transactions\":[],\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"uncles\":[]},\"id\":2}\n", |
||||
"headers": { |
||||
"Date": "Thu, 01 Feb 2018 19:05:58 GMT", |
||||
"Content-Type": "application/json", |
||||
"Transfer-Encoding": "chunked", |
||||
"Connection": "keep-alive", |
||||
"Set-Cookie": "__cfduid=d9d19faf0437d02b6374eec22299851e11517511958; expires=Fri, 01-Feb-19 19:05:58 GMT; path=/; domain=.poa.network; HttpOnly; Secure", |
||||
"Expect-CT": "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", |
||||
"Server": "cloudflare", |
||||
"CF-RAY": "3e672f6c0a1b9378-SJC" |
||||
}, |
||||
"status_code": 200, |
||||
"type": "ok" |
||||
} |
||||
} |
||||
] |
@ -0,0 +1,30 @@ |
||||
[ |
||||
{ |
||||
"request": { |
||||
"body": "{\"params\":[\"1\",true],\"method\":\"eth_getBlockByNumber\",\"jsonrpc\":\"2.0\",\"id\":0}", |
||||
"headers": { |
||||
"Content-Type": "application/json" |
||||
}, |
||||
"method": "post", |
||||
"options": [], |
||||
"request_body": "", |
||||
"url": "https://sokol.poa.network:443" |
||||
}, |
||||
"response": { |
||||
"binary": false, |
||||
"body": "{\"jsonrpc\":\"2.0\",\"result\":{\"author\":\"0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca\",\"difficulty\":\"0xffffffffffffffffffffffffedf58e45\",\"extraData\":\"0xd5830108048650617269747986312e32322e31826c69\",\"gasLimit\":\"0x66556d\",\"gasUsed\":\"0x0\",\"hash\":\"0x52c867bc0a91e573dc39300143c3bead7408d09d45bdb686749f02684ece72f3\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca\",\"number\":\"0x1\",\"parentHash\":\"0x5b28c1bfd3a15230c9a46b399cd0f9a6920d432e85381cc6a140b06e8410112f\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"sealFields\":[\"0x84120a71ba\",\"0xb8417a5887662f09ac4673af5850d28f3ad6550407b9c814ef563a13320f881b55ef03754f48f2dde027ad4a5abcabcc42780d9ebfc645f183e5252507d6a25bc2ec01\"],\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"signature\":\"7a5887662f09ac4673af5850d28f3ad6550407b9c814ef563a13320f881b55ef03754f48f2dde027ad4a5abcabcc42780d9ebfc645f183e5252507d6a25bc2ec01\",\"size\":\"0x240\",\"stateRoot\":\"0xc196ad59d867542ef20b29df5f418d07dc7234f4bc3d25260526620b7958a8fb\",\"step\":\"302674362\",\"timestamp\":\"0x5a3438a2\",\"totalDifficulty\":\"0xffffffffffffffffffffffffedf78e45\",\"transactions\":[],\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"uncles\":[]},\"id\":0}\n", |
||||
"headers": { |
||||
"Date": "Thu, 01 Feb 2018 19:01:24 GMT", |
||||
"Content-Type": "application/json", |
||||
"Transfer-Encoding": "chunked", |
||||
"Connection": "keep-alive", |
||||
"Set-Cookie": "__cfduid=dd5b42dc11eb34648ef3c5b13cd49fe5c1517511684; expires=Fri, 01-Feb-19 19:01:24 GMT; path=/; domain=.poa.network; HttpOnly; Secure", |
||||
"Expect-CT": "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", |
||||
"Server": "cloudflare", |
||||
"CF-RAY": "3e6728ba88d192b2-SJC" |
||||
}, |
||||
"status_code": 200, |
||||
"type": "ok" |
||||
} |
||||
} |
||||
] |
Loading…
Reference in new issue