diff --git a/.sqlx/query-07569ef79e07d80d00b7a103a91737419fc24f1e4bd26ef4dd0cc260c55f1f21.json b/.sqlx/query-07569ef79e07d80d00b7a103a91737419fc24f1e4bd26ef4dd0cc260c55f1f21.json index f7cd521..5001bbb 100644 --- a/.sqlx/query-07569ef79e07d80d00b7a103a91737419fc24f1e4bd26ef4dd0cc260c55f1f21.json +++ b/.sqlx/query-07569ef79e07d80d00b7a103a91737419fc24f1e4bd26ef4dd0cc260c55f1f21.json @@ -25,41 +25,31 @@ }, { "ordinal": 4, - "name": "validators_ed25519", - "type_info": "VarcharArray" - }, - { - "ordinal": 5, - "name": "validators_bandersnatches", - "type_info": "VarcharArray" - }, - { - "ordinal": 6, "name": "blocks", "type_info": "Int4" }, { - "ordinal": 7, + "ordinal": 5, "name": "tickets", "type_info": "Int4" }, { - "ordinal": 8, + "ordinal": 6, "name": "preimages", "type_info": "Int4" }, { - "ordinal": 9, + "ordinal": 7, "name": "preimages_size", "type_info": "Int4" }, { - "ordinal": 10, + "ordinal": 8, "name": "guarantees", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 9, "name": "assurances", "type_info": "Int4" } @@ -79,8 +69,6 @@ false, false, false, - false, - false, false ] }, diff --git a/.sqlx/query-6e0a84040128b36e33ddda817aa976917d9a869346e3d744879cdcc3337a4934.json b/.sqlx/query-0c95075754a6c7163c578b60479dbc8c3402eda7b6296fb28894f2f0e234c8b9.json similarity index 71% rename from .sqlx/query-6e0a84040128b36e33ddda817aa976917d9a869346e3d744879cdcc3337a4934.json rename to .sqlx/query-0c95075754a6c7163c578b60479dbc8c3402eda7b6296fb28894f2f0e234c8b9.json index aa1b9a9..c8573b8 100644 --- a/.sqlx/query-6e0a84040128b36e33ddda817aa976917d9a869346e3d744879cdcc3337a4934.json +++ b/.sqlx/query-0c95075754a6c7163c578b60479dbc8c3402eda7b6296fb28894f2f0e234c8b9.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO headers (slot,hash,parent,parent_state_root,extrinsic_hash,extrinsic_count,author_index,entropy_source,seal,offenders_mark,current_epoch) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)", + "query": "INSERT INTO headers (slot,hash,parent,parent_state_root,extrinsic_hash,extrinsic_count,author_index,entropy_source,seal,offenders_mark,current_epoch,author_id) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)", "describe": { "columns": [], "parameters": { @@ -15,10 +15,11 @@ "Varchar", "Varchar", "VarcharArray", + "Int4", "Int4" ] }, "nullable": [] }, - "hash": "6e0a84040128b36e33ddda817aa976917d9a869346e3d744879cdcc3337a4934" + "hash": "0c95075754a6c7163c578b60479dbc8c3402eda7b6296fb28894f2f0e234c8b9" } diff --git a/.sqlx/query-ddc90ef501be37ed0ecc5c9edc87109cab1d6edd05eca76fec028c843f8865ee.json b/.sqlx/query-104a2d87228ddade162a703032d695c808c5d48f2a155b3320e0c36879f33fe9.json similarity index 87% rename from .sqlx/query-ddc90ef501be37ed0ecc5c9edc87109cab1d6edd05eca76fec028c843f8865ee.json rename to .sqlx/query-104a2d87228ddade162a703032d695c808c5d48f2a155b3320e0c36879f33fe9.json index 478c539..c4e12b9 100644 --- a/.sqlx/query-ddc90ef501be37ed0ecc5c9edc87109cab1d6edd05eca76fec028c843f8865ee.json +++ b/.sqlx/query-104a2d87228ddade162a703032d695c808c5d48f2a155b3320e0c36879f33fe9.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT * FROM cores WHERE vindex=$1 AND id<$2 ORDER BY id DESC LIMIT $3", + "query": "SELECT * FROM epochs_cores WHERE vindex=$1 AND id<$2 ORDER BY id DESC LIMIT $3", "describe": { "columns": [ { @@ -10,7 +10,7 @@ }, { "ordinal": 1, - "name": "epoch", + "name": "epoch_id", "type_info": "Int4" }, { @@ -80,5 +80,5 @@ false ] }, - "hash": "ddc90ef501be37ed0ecc5c9edc87109cab1d6edd05eca76fec028c843f8865ee" + "hash": "104a2d87228ddade162a703032d695c808c5d48f2a155b3320e0c36879f33fe9" } diff --git a/.sqlx/query-95e8d1616a6f70f44912886b539e3367002cb9455e9ad859c61e73fc45e1cc80.json b/.sqlx/query-1c2a55efd9cba19e78deb107b182bd139a3ad009dd2b95497631051b7d26f2da.json similarity index 58% rename from .sqlx/query-95e8d1616a6f70f44912886b539e3367002cb9455e9ad859c61e73fc45e1cc80.json rename to .sqlx/query-1c2a55efd9cba19e78deb107b182bd139a3ad009dd2b95497631051b7d26f2da.json index 2ef8104..5abde2d 100644 --- a/.sqlx/query-95e8d1616a6f70f44912886b539e3367002cb9455e9ad859c61e73fc45e1cc80.json +++ b/.sqlx/query-1c2a55efd9cba19e78deb107b182bd139a3ad009dd2b95497631051b7d26f2da.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE epochs SET block=$1,entropy=$2,tickets_entropy=$3,validators_ed25519=$4,validators_bandersnatches=$5 WHERE id = $6", + "query": "UPDATE epochs SET block=$1,entropy=$2,tickets_entropy=$3 WHERE id = $4", "describe": { "columns": [], "parameters": { @@ -8,12 +8,10 @@ "Int4", "Varchar", "Varchar", - "VarcharArray", - "VarcharArray", "Int4" ] }, "nullable": [] }, - "hash": "95e8d1616a6f70f44912886b539e3367002cb9455e9ad859c61e73fc45e1cc80" + "hash": "1c2a55efd9cba19e78deb107b182bd139a3ad009dd2b95497631051b7d26f2da" } diff --git a/.sqlx/query-60ec4afde2a4783808bad7b7c83b1ab6c68846d2f757a4759b746cf5feff84ea.json b/.sqlx/query-200b26e8a0c06ea89aa26a3100e28072fb8ec605cdd2c9d77c1813b63993f73e.json similarity index 76% rename from .sqlx/query-60ec4afde2a4783808bad7b7c83b1ab6c68846d2f757a4759b746cf5feff84ea.json rename to .sqlx/query-200b26e8a0c06ea89aa26a3100e28072fb8ec605cdd2c9d77c1813b63993f73e.json index 9ec5e8f..1c147cb 100644 --- a/.sqlx/query-60ec4afde2a4783808bad7b7c83b1ab6c68846d2f757a4759b746cf5feff84ea.json +++ b/.sqlx/query-200b26e8a0c06ea89aa26a3100e28072fb8ec605cdd2c9d77c1813b63993f73e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT * FROM validators WHERE vindex=$1 AND id<$2 ORDER BY id DESC LIMIT $3", + "query": "SELECT * FROM epochs_validators WHERE validator_id=$1 AND id<$2 ORDER BY id DESC LIMIT $3", "describe": { "columns": [ { @@ -10,36 +10,41 @@ }, { "ordinal": 1, - "name": "epoch", + "name": "epoch_id", "type_info": "Int4" }, { "ordinal": 2, - "name": "vindex", + "name": "validator_id", "type_info": "Int4" }, { "ordinal": 3, - "name": "blocks", + "name": "vindex", "type_info": "Int4" }, { "ordinal": 4, - "name": "tickets", + "name": "blocks", "type_info": "Int4" }, { "ordinal": 5, - "name": "preimages", + "name": "tickets", "type_info": "Int4" }, { "ordinal": 6, - "name": "guarantees", + "name": "preimages", "type_info": "Int4" }, { "ordinal": 7, + "name": "guarantees", + "type_info": "Int4" + }, + { + "ordinal": 8, "name": "assurances", "type_info": "Int4" } @@ -59,8 +64,9 @@ false, false, false, + false, false ] }, - "hash": "60ec4afde2a4783808bad7b7c83b1ab6c68846d2f757a4759b746cf5feff84ea" + "hash": "200b26e8a0c06ea89aa26a3100e28072fb8ec605cdd2c9d77c1813b63993f73e" } diff --git a/.sqlx/query-719313db98c8564580bc6313c1c781a628adc479bb39886db0434b21e6381ff1.json b/.sqlx/query-213fefde33bea711aa0c474121d99e1109c742658d140ec65d486b151b089f6c.json similarity index 53% rename from .sqlx/query-719313db98c8564580bc6313c1c781a628adc479bb39886db0434b21e6381ff1.json rename to .sqlx/query-213fefde33bea711aa0c474121d99e1109c742658d140ec65d486b151b089f6c.json index e37b125..d8edd09 100644 --- a/.sqlx/query-719313db98c8564580bc6313c1c781a628adc479bb39886db0434b21e6381ff1.json +++ b/.sqlx/query-213fefde33bea711aa0c474121d99e1109c742658d140ec65d486b151b089f6c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO epochs (id, block,entropy,tickets_entropy,validators_ed25519,validators_bandersnatches) VALUES ($1,$2,$3,$4,$5,$6)", + "query": "INSERT INTO epochs (id, block,entropy,tickets_entropy) VALUES ($1,$2,$3,$4)", "describe": { "columns": [], "parameters": { @@ -8,12 +8,10 @@ "Int4", "Int4", "Varchar", - "Varchar", - "VarcharArray", - "VarcharArray" + "Varchar" ] }, "nullable": [] }, - "hash": "719313db98c8564580bc6313c1c781a628adc479bb39886db0434b21e6381ff1" + "hash": "213fefde33bea711aa0c474121d99e1109c742658d140ec65d486b151b089f6c" } diff --git a/.sqlx/query-2360cb8ef3e53a347aaecf6c7eb07c9359e28c335c0a9207059a8e798cdbf5b1.json b/.sqlx/query-2360cb8ef3e53a347aaecf6c7eb07c9359e28c335c0a9207059a8e798cdbf5b1.json new file mode 100644 index 0000000..67887b7 --- /dev/null +++ b/.sqlx/query-2360cb8ef3e53a347aaecf6c7eb07c9359e28c335c0a9207059a8e798cdbf5b1.json @@ -0,0 +1,70 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM validators WHERE ed25519 = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "ed25519", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "bandersnatch", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "details", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "software", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "ip", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "website", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "scores", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "2360cb8ef3e53a347aaecf6c7eb07c9359e28c335c0a9207059a8e798cdbf5b1" +} diff --git a/.sqlx/query-54d198a2baf78138b47590b7ffcc69751b59ff37bd2fdbe71200776b11cf1c8a.json b/.sqlx/query-2781f912636c9a61536f9f652e76593a5feebb21f1b4e9e5ce028ed0d5345b15.json similarity index 87% rename from .sqlx/query-54d198a2baf78138b47590b7ffcc69751b59ff37bd2fdbe71200776b11cf1c8a.json rename to .sqlx/query-2781f912636c9a61536f9f652e76593a5feebb21f1b4e9e5ce028ed0d5345b15.json index 640f3a6..03bfe55 100644 --- a/.sqlx/query-54d198a2baf78138b47590b7ffcc69751b59ff37bd2fdbe71200776b11cf1c8a.json +++ b/.sqlx/query-2781f912636c9a61536f9f652e76593a5feebb21f1b4e9e5ce028ed0d5345b15.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT * FROM cores WHERE epoch=$1 AND id>$2 ORDER BY id ASC LIMIT $3", + "query": "SELECT * FROM epochs_cores WHERE epoch_id=$1 AND id>$2 ORDER BY id ASC LIMIT $3", "describe": { "columns": [ { @@ -10,7 +10,7 @@ }, { "ordinal": 1, - "name": "epoch", + "name": "epoch_id", "type_info": "Int4" }, { @@ -80,5 +80,5 @@ false ] }, - "hash": "54d198a2baf78138b47590b7ffcc69751b59ff37bd2fdbe71200776b11cf1c8a" + "hash": "2781f912636c9a61536f9f652e76593a5feebb21f1b4e9e5ce028ed0d5345b15" } diff --git a/.sqlx/query-59bba6b0772ee07689dc4fdb55d7aa408df8a170e05a543af0582645698c334f.json b/.sqlx/query-4709cd8fd7f9c55919f1a239cc1884299d5f89473bf99b7402399641706729a8.json similarity index 88% rename from .sqlx/query-59bba6b0772ee07689dc4fdb55d7aa408df8a170e05a543af0582645698c334f.json rename to .sqlx/query-4709cd8fd7f9c55919f1a239cc1884299d5f89473bf99b7402399641706729a8.json index db4960c..35a5fd0 100644 --- a/.sqlx/query-59bba6b0772ee07689dc4fdb55d7aa408df8a170e05a543af0582645698c334f.json +++ b/.sqlx/query-4709cd8fd7f9c55919f1a239cc1884299d5f89473bf99b7402399641706729a8.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT * from cores WHERE vindex = $1 AND epoch = $2", + "query": "SELECT * from epochs_cores WHERE vindex = $1 AND epoch_id = $2", "describe": { "columns": [ { @@ -10,7 +10,7 @@ }, { "ordinal": 1, - "name": "epoch", + "name": "epoch_id", "type_info": "Int4" }, { @@ -79,5 +79,5 @@ false ] }, - "hash": "59bba6b0772ee07689dc4fdb55d7aa408df8a170e05a543af0582645698c334f" + "hash": "4709cd8fd7f9c55919f1a239cc1884299d5f89473bf99b7402399641706729a8" } diff --git a/.sqlx/query-9d7da9189af05adc987f67bd2225894deb4dbdb3b5934aa3dedaf6841758039c.json b/.sqlx/query-47e834e7743e049c59c83090b33c7a0a41920553b168f0563e7ad31f9ca3a03b.json similarity index 77% rename from .sqlx/query-9d7da9189af05adc987f67bd2225894deb4dbdb3b5934aa3dedaf6841758039c.json rename to .sqlx/query-47e834e7743e049c59c83090b33c7a0a41920553b168f0563e7ad31f9ca3a03b.json index 3c81a25..3e20726 100644 --- a/.sqlx/query-9d7da9189af05adc987f67bd2225894deb4dbdb3b5934aa3dedaf6841758039c.json +++ b/.sqlx/query-47e834e7743e049c59c83090b33c7a0a41920553b168f0563e7ad31f9ca3a03b.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT * FROM validators WHERE epoch=$1", + "query": "SELECT * FROM epochs_validators WHERE epoch_id=$1", "describe": { "columns": [ { @@ -10,36 +10,41 @@ }, { "ordinal": 1, - "name": "epoch", + "name": "epoch_id", "type_info": "Int4" }, { "ordinal": 2, - "name": "vindex", + "name": "validator_id", "type_info": "Int4" }, { "ordinal": 3, - "name": "blocks", + "name": "vindex", "type_info": "Int4" }, { "ordinal": 4, - "name": "tickets", + "name": "blocks", "type_info": "Int4" }, { "ordinal": 5, - "name": "preimages", + "name": "tickets", "type_info": "Int4" }, { "ordinal": 6, - "name": "guarantees", + "name": "preimages", "type_info": "Int4" }, { "ordinal": 7, + "name": "guarantees", + "type_info": "Int4" + }, + { + "ordinal": 8, "name": "assurances", "type_info": "Int4" } @@ -57,8 +62,9 @@ false, false, false, + false, false ] }, - "hash": "9d7da9189af05adc987f67bd2225894deb4dbdb3b5934aa3dedaf6841758039c" + "hash": "47e834e7743e049c59c83090b33c7a0a41920553b168f0563e7ad31f9ca3a03b" } diff --git a/.sqlx/query-5c8351f11ac2f11a255491f5e8d4132249e8fafcf7b1ce29e065351720328ca9.json b/.sqlx/query-5c8351f11ac2f11a255491f5e8d4132249e8fafcf7b1ce29e065351720328ca9.json index e861a7b..cb765fc 100644 --- a/.sqlx/query-5c8351f11ac2f11a255491f5e8d4132249e8fafcf7b1ce29e065351720328ca9.json +++ b/.sqlx/query-5c8351f11ac2f11a255491f5e8d4132249e8fafcf7b1ce29e065351720328ca9.json @@ -25,41 +25,31 @@ }, { "ordinal": 4, - "name": "validators_ed25519", - "type_info": "VarcharArray" - }, - { - "ordinal": 5, - "name": "validators_bandersnatches", - "type_info": "VarcharArray" - }, - { - "ordinal": 6, "name": "blocks", "type_info": "Int4" }, { - "ordinal": 7, + "ordinal": 5, "name": "tickets", "type_info": "Int4" }, { - "ordinal": 8, + "ordinal": 6, "name": "preimages", "type_info": "Int4" }, { - "ordinal": 9, + "ordinal": 7, "name": "preimages_size", "type_info": "Int4" }, { - "ordinal": 10, + "ordinal": 8, "name": "guarantees", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 9, "name": "assurances", "type_info": "Int4" } @@ -79,8 +69,6 @@ false, false, false, - false, - false, false ] }, diff --git a/.sqlx/query-7a006fddbb9c700acc3d4670aef4c571a0a2fe1a6aee80c172abae04d9f9e3d4.json b/.sqlx/query-7a006fddbb9c700acc3d4670aef4c571a0a2fe1a6aee80c172abae04d9f9e3d4.json new file mode 100644 index 0000000..c78ea43 --- /dev/null +++ b/.sqlx/query-7a006fddbb9c700acc3d4670aef4c571a0a2fe1a6aee80c172abae04d9f9e3d4.json @@ -0,0 +1,90 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM headers WHERE author_id=$1 AND slot<$2 ORDER BY slot DESC LIMIT $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "slot", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "hash", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "parent", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "parent_state_root", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "extrinsic_hash", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "extrinsic_count", + "type_info": "Int4" + }, + { + "ordinal": 6, + "name": "author_index", + "type_info": "Int4" + }, + { + "ordinal": 7, + "name": "entropy_source", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "seal", + "type_info": "Varchar" + }, + { + "ordinal": 9, + "name": "offenders_mark", + "type_info": "VarcharArray" + }, + { + "ordinal": 10, + "name": "current_epoch", + "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "author_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4", + "Int4", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "7a006fddbb9c700acc3d4670aef4c571a0a2fe1a6aee80c172abae04d9f9e3d4" +} diff --git a/.sqlx/query-e0950651e01e8780810f5b40c0311616bc3ae717ace6b93c9f6a9cab2e79555c.json b/.sqlx/query-8766aa1a236194314d650d2c97346b309ea00f8fdc97c350c4af341898fc1166.json similarity index 54% rename from .sqlx/query-e0950651e01e8780810f5b40c0311616bc3ae717ace6b93c9f6a9cab2e79555c.json rename to .sqlx/query-8766aa1a236194314d650d2c97346b309ea00f8fdc97c350c4af341898fc1166.json index 8d5e7a8..04533eb 100644 --- a/.sqlx/query-e0950651e01e8780810f5b40c0311616bc3ae717ace6b93c9f6a9cab2e79555c.json +++ b/.sqlx/query-8766aa1a236194314d650d2c97346b309ea00f8fdc97c350c4af341898fc1166.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE cores SET gas_used=$1,imports=$2,extrinsic_count=$3,extrinsic_size=$4,exports=$5,bundle_size=$6,da_load=$7,popularity=$8 WHERE id = $9", + "query": "UPDATE epochs_cores SET gas_used=$1,imports=$2,extrinsic_count=$3,extrinsic_size=$4,exports=$5,bundle_size=$6,da_load=$7,popularity=$8 WHERE id = $9", "describe": { "columns": [], "parameters": { @@ -18,5 +18,5 @@ }, "nullable": [] }, - "hash": "e0950651e01e8780810f5b40c0311616bc3ae717ace6b93c9f6a9cab2e79555c" + "hash": "8766aa1a236194314d650d2c97346b309ea00f8fdc97c350c4af341898fc1166" } diff --git a/.sqlx/query-b2592bc734606f2342b77b86664d41fa29da34c1b919d60c808d1a75539479b1.json b/.sqlx/query-897dfec3f407633d621c2d7292e19117370e00dbdfc9f67d8ec85629d6fafe5e.json similarity index 50% rename from .sqlx/query-b2592bc734606f2342b77b86664d41fa29da34c1b919d60c808d1a75539479b1.json rename to .sqlx/query-897dfec3f407633d621c2d7292e19117370e00dbdfc9f67d8ec85629d6fafe5e.json index 3a9e400..66c2cb5 100644 --- a/.sqlx/query-b2592bc734606f2342b77b86664d41fa29da34c1b919d60c808d1a75539479b1.json +++ b/.sqlx/query-897dfec3f407633d621c2d7292e19117370e00dbdfc9f67d8ec85629d6fafe5e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO validators (epoch,vindex,blocks,tickets,preimages,guarantees,assurances) VALUES ($1,$2,$3,$4,$5,$6,$7)", + "query": "INSERT INTO epochs_validators (epoch_id,validator_id,vindex,blocks,tickets,preimages,guarantees,assurances) VALUES ($1,$2,$3,$4,$5,$6,$7,$8)", "describe": { "columns": [], "parameters": { @@ -11,10 +11,11 @@ "Int4", "Int4", "Int4", + "Int4", "Int4" ] }, "nullable": [] }, - "hash": "b2592bc734606f2342b77b86664d41fa29da34c1b919d60c808d1a75539479b1" + "hash": "897dfec3f407633d621c2d7292e19117370e00dbdfc9f67d8ec85629d6fafe5e" } diff --git a/.sqlx/query-65303a075d1a413966c5804ceaadb737e440f471b68403109a9b1c24a8603847.json b/.sqlx/query-90b4a4897fafc7939c8661864b1485d56f254f00dc8bf073d5852c1d6f022c85.json similarity index 76% rename from .sqlx/query-65303a075d1a413966c5804ceaadb737e440f471b68403109a9b1c24a8603847.json rename to .sqlx/query-90b4a4897fafc7939c8661864b1485d56f254f00dc8bf073d5852c1d6f022c85.json index 479e059..6681a2a 100644 --- a/.sqlx/query-65303a075d1a413966c5804ceaadb737e440f471b68403109a9b1c24a8603847.json +++ b/.sqlx/query-90b4a4897fafc7939c8661864b1485d56f254f00dc8bf073d5852c1d6f022c85.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT * FROM validators WHERE epoch=$1 AND id>$2 ORDER BY id ASC LIMIT $3", + "query": "SELECT * FROM epochs_validators WHERE epoch_id=$1 AND id>$2 ORDER BY id ASC LIMIT $3", "describe": { "columns": [ { @@ -10,36 +10,41 @@ }, { "ordinal": 1, - "name": "epoch", + "name": "epoch_id", "type_info": "Int4" }, { "ordinal": 2, - "name": "vindex", + "name": "validator_id", "type_info": "Int4" }, { "ordinal": 3, - "name": "blocks", + "name": "vindex", "type_info": "Int4" }, { "ordinal": 4, - "name": "tickets", + "name": "blocks", "type_info": "Int4" }, { "ordinal": 5, - "name": "preimages", + "name": "tickets", "type_info": "Int4" }, { "ordinal": 6, - "name": "guarantees", + "name": "preimages", "type_info": "Int4" }, { "ordinal": 7, + "name": "guarantees", + "type_info": "Int4" + }, + { + "ordinal": 8, "name": "assurances", "type_info": "Int4" } @@ -59,8 +64,9 @@ false, false, false, + false, false ] }, - "hash": "65303a075d1a413966c5804ceaadb737e440f471b68403109a9b1c24a8603847" + "hash": "90b4a4897fafc7939c8661864b1485d56f254f00dc8bf073d5852c1d6f022c85" } diff --git a/.sqlx/query-92e5287dae4ea9d8389501a8439655bdf1d15eed122aa5bc9e0f6af5fb788953.json b/.sqlx/query-92e5287dae4ea9d8389501a8439655bdf1d15eed122aa5bc9e0f6af5fb788953.json index d105383..ce0ac96 100644 --- a/.sqlx/query-92e5287dae4ea9d8389501a8439655bdf1d15eed122aa5bc9e0f6af5fb788953.json +++ b/.sqlx/query-92e5287dae4ea9d8389501a8439655bdf1d15eed122aa5bc9e0f6af5fb788953.json @@ -25,41 +25,31 @@ }, { "ordinal": 4, - "name": "validators_ed25519", - "type_info": "VarcharArray" - }, - { - "ordinal": 5, - "name": "validators_bandersnatches", - "type_info": "VarcharArray" - }, - { - "ordinal": 6, "name": "blocks", "type_info": "Int4" }, { - "ordinal": 7, + "ordinal": 5, "name": "tickets", "type_info": "Int4" }, { - "ordinal": 8, + "ordinal": 6, "name": "preimages", "type_info": "Int4" }, { - "ordinal": 9, + "ordinal": 7, "name": "preimages_size", "type_info": "Int4" }, { - "ordinal": 10, + "ordinal": 8, "name": "guarantees", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 9, "name": "assurances", "type_info": "Int4" } @@ -77,8 +67,6 @@ false, false, false, - false, - false, false ] }, diff --git a/.sqlx/query-a1519954eadd0cde38baada5f93a7f4255b993a8767e2fa05c5cee7fdb05b633.json b/.sqlx/query-a1519954eadd0cde38baada5f93a7f4255b993a8767e2fa05c5cee7fdb05b633.json new file mode 100644 index 0000000..88cb918 --- /dev/null +++ b/.sqlx/query-a1519954eadd0cde38baada5f93a7f4255b993a8767e2fa05c5cee7fdb05b633.json @@ -0,0 +1,70 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM validators WHERE ed25519=$1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "ed25519", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "bandersnatch", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "details", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "software", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "ip", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "website", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "scores", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "a1519954eadd0cde38baada5f93a7f4255b993a8767e2fa05c5cee7fdb05b633" +} diff --git a/.sqlx/query-a684805cc91a17aab82e4b26845ce9e90089455b73664a6f14053ff6f6ae0d1d.json b/.sqlx/query-a684805cc91a17aab82e4b26845ce9e90089455b73664a6f14053ff6f6ae0d1d.json new file mode 100644 index 0000000..e327fb9 --- /dev/null +++ b/.sqlx/query-a684805cc91a17aab82e4b26845ce9e90089455b73664a6f14053ff6f6ae0d1d.json @@ -0,0 +1,71 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM epochs_validators WHERE epoch_id=$1 AND validator_id=$2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "epoch_id", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "validator_id", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "vindex", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "blocks", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "tickets", + "type_info": "Int4" + }, + { + "ordinal": 6, + "name": "preimages", + "type_info": "Int4" + }, + { + "ordinal": 7, + "name": "guarantees", + "type_info": "Int4" + }, + { + "ordinal": 8, + "name": "assurances", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4", + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "a684805cc91a17aab82e4b26845ce9e90089455b73664a6f14053ff6f6ae0d1d" +} diff --git a/.sqlx/query-a0fa3547efed14f1b092b130d2ccf60586f6fb90982567a97cd7a8deee58a31a.json b/.sqlx/query-ba8ed56957b08071cad169693c6d2a6a269e409d734e7679db36af9fc276568e.json similarity index 54% rename from .sqlx/query-a0fa3547efed14f1b092b130d2ccf60586f6fb90982567a97cd7a8deee58a31a.json rename to .sqlx/query-ba8ed56957b08071cad169693c6d2a6a269e409d734e7679db36af9fc276568e.json index d6cd722..2f2e95b 100644 --- a/.sqlx/query-a0fa3547efed14f1b092b130d2ccf60586f6fb90982567a97cd7a8deee58a31a.json +++ b/.sqlx/query-ba8ed56957b08071cad169693c6d2a6a269e409d734e7679db36af9fc276568e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE validators SET blocks=$1,tickets=$2,preimages=$3,guarantees=$4,assurances=$5 WHERE id=$6", + "query": "UPDATE epochs_validators SET blocks=$1,tickets=$2,preimages=$3,guarantees=$4,assurances=$5 WHERE id=$6", "describe": { "columns": [], "parameters": { @@ -15,5 +15,5 @@ }, "nullable": [] }, - "hash": "a0fa3547efed14f1b092b130d2ccf60586f6fb90982567a97cd7a8deee58a31a" + "hash": "ba8ed56957b08071cad169693c6d2a6a269e409d734e7679db36af9fc276568e" } diff --git a/.sqlx/query-106b9dfb7aa60463eed6e7b40920df87d1b01ca1c02a9a75d6bba31b8291656c.json b/.sqlx/query-bcd04c873204b3e2b6d0589dfe496e027449f7f16eb6e98b328f6863a9e884df.json similarity index 53% rename from .sqlx/query-106b9dfb7aa60463eed6e7b40920df87d1b01ca1c02a9a75d6bba31b8291656c.json rename to .sqlx/query-bcd04c873204b3e2b6d0589dfe496e027449f7f16eb6e98b328f6863a9e884df.json index 3254314..297cb28 100644 --- a/.sqlx/query-106b9dfb7aa60463eed6e7b40920df87d1b01ca1c02a9a75d6bba31b8291656c.json +++ b/.sqlx/query-bcd04c873204b3e2b6d0589dfe496e027449f7f16eb6e98b328f6863a9e884df.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO cores (epoch,vindex,gas_used,imports,extrinsic_count,extrinsic_size,exports,bundle_size,da_load,popularity) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)", + "query": "INSERT INTO epochs_cores (epoch_id,vindex,gas_used,imports,extrinsic_count,extrinsic_size,exports,bundle_size,da_load,popularity) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)", "describe": { "columns": [], "parameters": { @@ -19,5 +19,5 @@ }, "nullable": [] }, - "hash": "106b9dfb7aa60463eed6e7b40920df87d1b01ca1c02a9a75d6bba31b8291656c" + "hash": "bcd04c873204b3e2b6d0589dfe496e027449f7f16eb6e98b328f6863a9e884df" } diff --git a/.sqlx/query-bd82a6e4d74c28b42a331c8565493b4c27912b536276d5f33d63b6bfb7ed42ce.json b/.sqlx/query-bd82a6e4d74c28b42a331c8565493b4c27912b536276d5f33d63b6bfb7ed42ce.json index 28a7817..37a6104 100644 --- a/.sqlx/query-bd82a6e4d74c28b42a331c8565493b4c27912b536276d5f33d63b6bfb7ed42ce.json +++ b/.sqlx/query-bd82a6e4d74c28b42a331c8565493b4c27912b536276d5f33d63b6bfb7ed42ce.json @@ -57,6 +57,11 @@ "ordinal": 10, "name": "current_epoch", "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "author_id", + "type_info": "Int4" } ], "parameters": { @@ -75,6 +80,7 @@ false, false, false, + false, false ] }, diff --git a/.sqlx/query-bec94f16a052d33869bb4f017167c4789174dee99f4e2c76fceba78a763d5fb7.json b/.sqlx/query-bec94f16a052d33869bb4f017167c4789174dee99f4e2c76fceba78a763d5fb7.json new file mode 100644 index 0000000..425d853 --- /dev/null +++ b/.sqlx/query-bec94f16a052d33869bb4f017167c4789174dee99f4e2c76fceba78a763d5fb7.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT slot FROM blocks WHERE slot=$1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "slot", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false + ] + }, + "hash": "bec94f16a052d33869bb4f017167c4789174dee99f4e2c76fceba78a763d5fb7" +} diff --git a/.sqlx/query-c479a4eea20caaa0fea9739a2ffe509ed28a25b031398e661317c77310ac597c.json b/.sqlx/query-c479a4eea20caaa0fea9739a2ffe509ed28a25b031398e661317c77310ac597c.json new file mode 100644 index 0000000..332c22c --- /dev/null +++ b/.sqlx/query-c479a4eea20caaa0fea9739a2ffe509ed28a25b031398e661317c77310ac597c.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO validators (ed25519,bandersnatch) VALUES ($1, $2) RETURNING id", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Varchar" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c479a4eea20caaa0fea9739a2ffe509ed28a25b031398e661317c77310ac597c" +} diff --git a/.sqlx/query-e8d639646db6454a8aa70f35ea0692ccf970e33b3de47d09598498c3a1f0125b.json b/.sqlx/query-e8d639646db6454a8aa70f35ea0692ccf970e33b3de47d09598498c3a1f0125b.json index ce11bcc..47ce0db 100644 --- a/.sqlx/query-e8d639646db6454a8aa70f35ea0692ccf970e33b3de47d09598498c3a1f0125b.json +++ b/.sqlx/query-e8d639646db6454a8aa70f35ea0692ccf970e33b3de47d09598498c3a1f0125b.json @@ -57,6 +57,11 @@ "ordinal": 10, "name": "current_epoch", "type_info": "Int4" + }, + { + "ordinal": 11, + "name": "author_id", + "type_info": "Int4" } ], "parameters": { @@ -76,6 +81,7 @@ false, false, false, + false, false ] }, diff --git a/.sqlx/query-eaebc37b44255311a3f0b5ed8475de6620272c0c3878d8f11a31d8b7b08400cd.json b/.sqlx/query-eaebc37b44255311a3f0b5ed8475de6620272c0c3878d8f11a31d8b7b08400cd.json new file mode 100644 index 0000000..11e05e5 --- /dev/null +++ b/.sqlx/query-eaebc37b44255311a3f0b5ed8475de6620272c0c3878d8f11a31d8b7b08400cd.json @@ -0,0 +1,70 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM validators WHERE id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "ed25519", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "bandersnatch", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "details", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "software", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "ip", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "website", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "scores", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "eaebc37b44255311a3f0b5ed8475de6620272c0c3878d8f11a31d8b7b08400cd" +} diff --git a/.sqlx/query-ed84770d2ed8b8600593a18e7a8d56973dd8c7cbd2c7848f310e20c94ed6aed1.json b/.sqlx/query-ed84770d2ed8b8600593a18e7a8d56973dd8c7cbd2c7848f310e20c94ed6aed1.json index e76502b..cfe0e03 100644 --- a/.sqlx/query-ed84770d2ed8b8600593a18e7a8d56973dd8c7cbd2c7848f310e20c94ed6aed1.json +++ b/.sqlx/query-ed84770d2ed8b8600593a18e7a8d56973dd8c7cbd2c7848f310e20c94ed6aed1.json @@ -25,41 +25,31 @@ }, { "ordinal": 4, - "name": "validators_ed25519", - "type_info": "VarcharArray" - }, - { - "ordinal": 5, - "name": "validators_bandersnatches", - "type_info": "VarcharArray" - }, - { - "ordinal": 6, "name": "blocks", "type_info": "Int4" }, { - "ordinal": 7, + "ordinal": 5, "name": "tickets", "type_info": "Int4" }, { - "ordinal": 8, + "ordinal": 6, "name": "preimages", "type_info": "Int4" }, { - "ordinal": 9, + "ordinal": 7, "name": "preimages_size", "type_info": "Int4" }, { - "ordinal": 10, + "ordinal": 8, "name": "guarantees", "type_info": "Int4" }, { - "ordinal": 11, + "ordinal": 9, "name": "assurances", "type_info": "Int4" } @@ -79,8 +69,6 @@ false, false, false, - false, - false, false ] }, diff --git a/migrations/20250505144856_headers.sql b/migrations/20250505144856_headers.sql index bff40b3..aa76fd3 100644 --- a/migrations/20250505144856_headers.sql +++ b/migrations/20250505144856_headers.sql @@ -10,5 +10,7 @@ CREATE TABLE IF NOT EXISTS headers ( entropy_source VARCHAR NOT NULL, seal VARCHAR NOT NULL, offenders_mark VARCHAR[] NOT NULL, - current_epoch INT NOT NULL -) + current_epoch INT NOT NULL, + author_id INT NOT NULL +); +CREATE INDEX idx_headers_author ON headers (author_id); diff --git a/migrations/20250506044800_epochs.sql b/migrations/20250506044800_epochs.sql index 4999153..458d47e 100644 --- a/migrations/20250506044800_epochs.sql +++ b/migrations/20250506044800_epochs.sql @@ -1,11 +1,9 @@ -- Add migration script here CREATE TABLE IF NOT EXISTS epochs ( id INT PRIMARY KEY, - block INT NOT NULL REFERENCES blocks(slot), + block INT NOT NULL, entropy VARCHAR NOT NULL, -- TODO: should be unique in production tickets_entropy VARCHAR NOT NULL, - validators_ed25519 VARCHAR[] NOT NULL, - validators_bandersnatches VARCHAR[] NOT NULL, blocks INT NOT NULL DEFAULT 0, tickets INT NOT NULL DEFAULT 0, preimages INT NOT NULL DEFAULT 0, diff --git a/migrations/20250509064251_validators.sql b/migrations/20250509064251_validators.sql new file mode 100644 index 0000000..8b2f9b5 --- /dev/null +++ b/migrations/20250509064251_validators.sql @@ -0,0 +1,12 @@ +-- Add migration script here +CREATE TABLE IF NOT EXISTS validators ( + id SERIAL PRIMARY KEY, + ed25519 VARCHAR NOT NULL UNIQUE, + bandersnatch VARCHAR NOT NULL, + name VARCHAR NOT NULL default '', + details TEXT NOT NULL default '', + software VARCHAR NOT NULL default '', + ip VARCHAR NOT NULL default '', + website VARCHAR NOT NULL default '', + scores INT NOT NULL default 0 +) diff --git a/migrations/20250509065251_cores.sql b/migrations/20250509065251_cores.sql new file mode 100644 index 0000000..8ddc1d3 --- /dev/null +++ b/migrations/20250509065251_cores.sql @@ -0,0 +1 @@ +-- Add migration script here diff --git a/migrations/20250510011826_epochs_validators.sql b/migrations/20250510011826_epochs_validators.sql new file mode 100644 index 0000000..413365e --- /dev/null +++ b/migrations/20250510011826_epochs_validators.sql @@ -0,0 +1,14 @@ +-- Add migration script here +CREATE TABLE IF NOT EXISTS epochs_validators ( + id SERIAL PRIMARY KEY, + epoch_id INT NOT NULL, + validator_id INT NOT NULL, + vindex INT NOT NULL, + blocks INT NOT NULL, + tickets INT NOT NULL, + preimages INT NOT NULL, + guarantees INT NOT NULL, + assurances INT NOT NULL +); +CREATE INDEX idx_validators_epoch ON epochs_validators (epoch_id); +CREATE INDEX idx_validators_validator ON epochs_validators (validator_id); diff --git a/migrations/20250510011826_validators.sql b/migrations/20250510011826_validators.sql deleted file mode 100644 index 7d91ff7..0000000 --- a/migrations/20250510011826_validators.sql +++ /dev/null @@ -1,13 +0,0 @@ --- Add migration script here -CREATE TABLE IF NOT EXISTS validators ( - id SERIAL PRIMARY KEY, - epoch INT NOT NULL, - vindex INT NOT NULL, - blocks INT NOT NULL, - tickets INT NOT NULL, - preimages INT NOT NULL, - guarantees INT NOT NULL, - assurances INT NOT NULL -); -CREATE INDEX idx_validators_epoch ON validators (epoch); -CREATE INDEX idx_validators_vindex ON validators (vindex); diff --git a/migrations/20250510102002_cores.sql b/migrations/20250510102002_epochs_cores.sql similarity index 62% rename from migrations/20250510102002_cores.sql rename to migrations/20250510102002_epochs_cores.sql index 3446c5c..b241d65 100644 --- a/migrations/20250510102002_cores.sql +++ b/migrations/20250510102002_epochs_cores.sql @@ -1,7 +1,7 @@ -- Add migration script here -CREATE TABLE IF NOT EXISTS cores ( +CREATE TABLE IF NOT EXISTS epochs_cores ( id SERIAL PRIMARY KEY, - epoch INT NOT NULL, + epoch_id INT NOT NULL, vindex INT NOT NULL, gas_used BIGINT NOT NULL, imports INT NOT NULL, @@ -12,5 +12,5 @@ CREATE TABLE IF NOT EXISTS cores ( da_load BIGINT NOT NULL, popularity BIGINT NOT NULL ); -CREATE INDEX idx_cores_epoch ON cores (epoch); -CREATE INDEX idx_cores_vindex ON cores (vindex); +CREATE INDEX idx_cores_epoch ON epochs_cores (epoch_id); +CREATE INDEX idx_cores_vindex ON epochs_cores (vindex); diff --git a/schema.graphql b/schema.graphql index 3b3dfd3..c158cd7 100644 --- a/schema.graphql +++ b/schema.graphql @@ -28,6 +28,7 @@ type BlockHeader { extrinsicHash: String! extrinsicCount: Int! authorIndex: Int! + author: Validator! entropySource: String! seal: String! offendersMark: [String!]! @@ -35,49 +36,6 @@ type BlockHeader { ticketsMark: [Ticket!]! } -type Core { - id: Int! - epoch: Int! - vindex: Int! - gasUsed: Int! - imports: Int! - extrinsicCount: Int! - extrinsicSize: Int! - exports: Int! - bundleSize: Int! - daLoad: Int! - popularity: Int! -} - -type CoreConnection { - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - """ - A list of edges. - """ - edges: [CoreEdge!]! - """ - A list of nodes. - """ - nodes: [Core!]! -} - -""" -An edge in a connection. -""" -type CoreEdge { - """ - The item at the end of the edge - """ - node: Core! - """ - A cursor for use in pagination - """ - cursor: String! -} - type Dispute { verdicts: [DisputeVerdict!]! culprits: [DisputeCulprit!]! @@ -121,8 +79,6 @@ type Epoch { block: Int! entropy: String! ticketsEntropy: String! - validatorsEd25519: [String!]! - validatorsBandersnatches: [String!]! blocks: Int! tickets: Int! preimages: Int! @@ -134,13 +90,109 @@ type Epoch { Cursor for pagination """ after: String - ): ValidatorConnection! + ): EpochValidatorConnection! cores( first: Int = 10, """ Cursor for pagination """ after: String - ): CoreConnection! + ): EpochCoreConnection! +} + +type EpochCore { + id: Int! + epochId: Int! + vindex: Int! + gasUsed: Int! + imports: Int! + extrinsicCount: Int! + extrinsicSize: Int! + exports: Int! + bundleSize: Int! + daLoad: Int! + popularity: Int! + """ + Get the Epoch + """ + epoch: Epoch! +} + +type EpochCoreConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + """ + A list of edges. + """ + edges: [EpochCoreEdge!]! + """ + A list of nodes. + """ + nodes: [EpochCore!]! +} + +""" +An edge in a connection. +""" +type EpochCoreEdge { + """ + The item at the end of the edge + """ + node: EpochCore! + """ + A cursor for use in pagination + """ + cursor: String! +} + +type EpochValidator { + id: Int! + epochId: Int! + validatorId: Int! + vindex: Int! + blocks: Int! + tickets: Int! + preimages: Int! + guarantees: Int! + assurances: Int! + """ + Get the Epoch + """ + epoch: Epoch! + """ + Get the Validator + """ + validator: Validator! +} + +type EpochValidatorConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + """ + A list of edges. + """ + edges: [EpochValidatorEdge!]! + """ + A list of nodes. + """ + nodes: [EpochValidator!]! +} + +""" +An edge in a connection. +""" +type EpochValidatorEdge { + """ + The item at the end of the edge + """ + node: EpochValidator! + """ + A cursor for use in pagination + """ + cursor: String! } """ @@ -188,6 +240,8 @@ type Header { seal: String! offendersMark: [String!]! currentEpoch: Int! + authorId: Int! + author: Validator! } type HeaderConnection { @@ -299,20 +353,15 @@ type QueryRoot { """ Get the block data from the database. """ - block(slot: Int!): Block! + block(slot: Int!): Block """ Get the epoch by id """ - epoch(id: Int!): Epoch! + epoch(id: Int!): Epoch """ - Get the validator with all epoch statistics + Get the epoch by id/ed25519 """ - validator( index: Int!, first: Int = 10, - """ - Cursor for pagination - """ - after: String - ): ValidatorConnection! + validator(id: Int, ed25519: String): Validator """ Get the core with all epoch statistics """ @@ -321,7 +370,7 @@ type QueryRoot { Cursor for pagination """ after: String - ): CoreConnection! + ): EpochCoreConnection! """ List all services """ @@ -334,7 +383,7 @@ type QueryRoot { """ Get the service """ - service(id: Int!): Service! + service(id: Int!): Service } type Service { @@ -454,13 +503,13 @@ type Spacejam { """ services: Int! """ + Current epoch + """ + epoch: Int! + """ The total number of extrinsics """ extrinsics: Int! - """ - Current epoch - """ - epoch: Int! } type Ticket { @@ -472,42 +521,32 @@ type Ticket { type Validator { id: Int! - epoch: Int! - vindex: Int! - blocks: Int! - tickets: Int! - preimages: Int! - guarantees: Int! - assurances: Int! -} - -type ValidatorConnection { - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - """ - A list of edges. - """ - edges: [ValidatorEdge!]! - """ - A list of nodes. - """ - nodes: [Validator!]! -} - -""" -An edge in a connection. -""" -type ValidatorEdge { - """ - The item at the end of the edge - """ - node: Validator! + ed25519: String! + bandersnatch: String! + name: String! + details: String! + software: String! + ip: String! + website: String! + scores: Int! + """ + List this validator's all epochs data (DESC) + """ + epochs( first: Int = 10, + """ + Cursor for pagination + """ + after: String + ): EpochValidatorConnection! """ - A cursor for use in pagination + List this validator's all anchor blocks (DESC) """ - cursor: String! + blocks( first: Int = 10, + """ + Cursor for pagination + """ + after: String + ): HeaderConnection! } type WorkResult { diff --git a/src/manager/hook.rs b/src/manager/hook.rs index 4d0bbbb..39cbc0d 100644 --- a/src/manager/hook.rs +++ b/src/manager/hook.rs @@ -2,7 +2,7 @@ use crate::{ Manager, - models::{Block, Core, Epoch, Service}, + models::{Block, Epoch, EpochCore, Service}, }; use anyhow::Result; use runtime::storage::Commit; @@ -127,7 +127,7 @@ impl runtime::Hook for Manager { // update core statistics for (index, core) in statistics.cores.iter().enumerate() { - let _ = Core::statistic(&self.pg, epoch, index as i32, core).await; + let _ = EpochCore::statistic(&self.pg, epoch, index as i32, core).await; } // handle service data diff --git a/src/manager/mod.rs b/src/manager/mod.rs index c3ca08e..e9cbcb9 100644 --- a/src/manager/mod.rs +++ b/src/manager/mod.rs @@ -3,7 +3,11 @@ use anyhow::Result; use redis::Client; pub use spacejam::Spacejam; -use sqlx::PgPool; +use sqlx::{ + PgPool, + any::{Any, install_default_drivers}, + migrate::MigrateDatabase, +}; use std::sync::Arc; use tokio::sync::RwLock; @@ -29,7 +33,12 @@ impl Manager { /// on creating the manager, we calculate the global state of the chain /// and save it to the redis pub async fn new(pg: &str, redis: &str) -> Result { + // setup database & migration + install_default_drivers(); + let _ = Any::create_database(pg).await; let pg = PgPool::connect(pg).await?; + migrate!().run(&pg).await.expect("Migrations failed"); + let redis = Arc::new(Client::open(redis)?); let spacejam = Arc::new(RwLock::new(Spacejam::init(&pg).await?)); diff --git a/src/models/assurance.rs b/src/models/assurance.rs index 0005ebb..595bcdc 100644 --- a/src/models/assurance.rs +++ b/src/models/assurance.rs @@ -1,11 +1,10 @@ +use crate::models::hex; use anyhow::Result; use async_graphql::SimpleObject; use score::extrinsic::AvailAssurance; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::models::hex; - #[derive(SimpleObject, Serialize, Deserialize)] pub struct Assurance { id: i32, diff --git a/src/models/block.rs b/src/models/block.rs index ebb6c48..5bc3568 100644 --- a/src/models/block.rs +++ b/src/models/block.rs @@ -1,8 +1,8 @@ use crate::{ Manager, models::{ - Assurance, DisputeCulprit, DisputeFault, DisputeVerdict, Envelope, Epoch, Guarantee, - Header, Preimage, Ticket, Validator, + Assurance, DisputeCulprit, DisputeFault, DisputeVerdict, Envelope, Epoch, EpochValidator, + Guarantee, Header, Preimage, Ticket, Validator, }, }; use anyhow::Result; @@ -21,6 +21,7 @@ pub struct BlockHeader { extrinsic_hash: String, extrinsic_count: i32, author_index: i32, + author: Validator, entropy_source: String, seal: String, offenders_mark: Vec, @@ -59,6 +60,7 @@ impl Block { let header = Header::get(pool, slot).await?; let epoch = Epoch::get_by_block(pool, slot).await.ok(); let tickets = Ticket::list_by_block(pool, slot).await?; + let validator = Validator::get(pool, header.author_id).await?; let block_header = BlockHeader { slot: header.slot, hash: header.hash, @@ -67,6 +69,7 @@ impl Block { extrinsic_hash: header.extrinsic_hash, extrinsic_count: header.extrinsic_count, author_index: header.author_index, + author: validator, entropy_source: header.entropy_source, seal: header.seal, offenders_mark: header.offenders_mark, @@ -109,19 +112,26 @@ impl Block { impl Block { /// Count total blocks in the database pub async fn count(pool: &PgPool) -> Result { - let count = sqlx::query_scalar!("SELECT COUNT(*) FROM blocks") + let count = query_scalar!("SELECT COUNT(*) FROM blocks") .fetch_one(pool) .await? .unwrap_or(0); Ok(count) } + /// Get the block data from the database. + pub async fn get(pool: &PgPool, slot: i32) -> Result { + let slot = query_scalar!("SELECT slot FROM blocks WHERE slot=$1", slot) + .fetch_one(pool) + .await?; + Ok(Block { slot }) + } + /// Get the raw block data from the database. pub async fn raw(pool: &PgPool, slot: i32) -> Result { let raw = query_scalar!("SELECT raw FROM blocks WHERE slot=$1", slot) .fetch_one(pool) .await?; - Ok(raw) } @@ -129,10 +139,12 @@ impl Block { let raw = serde_json::to_string(&block.clone().to_json()).unwrap_or("".to_owned()); let slot = block.header.slot as i32; + // save raw block query!("INSERT INTO blocks (slot,raw) VALUES ($1,$2)", slot, raw) .execute(pool) .await?; + // save epoch let epoch_id = if let Some(epoch) = &block.header.epoch_mark { Epoch::insert(pool, slot, epoch).await? } else { @@ -188,11 +200,8 @@ impl Block { DisputeFault::insert(pool, slot, fault).await?; } - // save header - Header::insert(pool, slot, extrinsic_count, epoch_id, &block.header).await?; - // save validators - Validator::new_block( + let author = EpochValidator::new_block( pool, epoch_id, block.header.author_index as i32, @@ -203,6 +212,9 @@ impl Block { ) .await?; + // save header + Header::insert(pool, slot, extrinsic_count, epoch_id, author, &block.header).await?; + Ok(epoch_id) } } diff --git a/src/models/core.rs b/src/models/core.rs index 28213a6..510904d 100644 --- a/src/models/core.rs +++ b/src/models/core.rs @@ -1,13 +1,15 @@ +use crate::{Manager, models::Epoch}; use anyhow::Result; -use async_graphql::SimpleObject; +use async_graphql::{ComplexObject, Context, Result as GraphqlResult, SimpleObject}; use score::statistic::CoreActivityRecord; use serde::{Deserialize, Serialize}; use sqlx::PgPool; #[derive(SimpleObject, Serialize, Deserialize)] -pub struct Core { +#[graphql(complex)] +pub struct EpochCore { pub id: i32, - epoch: i32, + epoch_id: i32, vindex: i32, gas_used: i64, imports: i32, @@ -19,7 +21,16 @@ pub struct Core { popularity: i64, } -impl Core { +#[ComplexObject] +impl EpochCore { + /// Get the Epoch + pub async fn epoch(&self, ctx: &Context<'_>) -> GraphqlResult { + let pool = &ctx.data::()?.pg; + Ok(Epoch::get(pool, self.epoch_id).await?) + } +} + +impl EpochCore { /// List all cores in the epoch (ASC) pub async fn list_by_epoch( pool: &PgPool, @@ -29,7 +40,7 @@ impl Core { ) -> Result> { let data = query_as!( Self, - "SELECT * FROM cores WHERE epoch=$1 AND id>$2 ORDER BY id ASC LIMIT $3", + "SELECT * FROM epochs_cores WHERE epoch_id=$1 AND id>$2 ORDER BY id ASC LIMIT $3", epoch, cursor, limit as i64 + 1 @@ -50,7 +61,7 @@ impl Core { let fixed_cursor = if cursor == 0 { i32::MAX } else { cursor }; let data = query_as!( Self, - "SELECT * FROM cores WHERE vindex=$1 AND id<$2 ORDER BY id DESC LIMIT $3", + "SELECT * FROM epochs_cores WHERE vindex=$1 AND id<$2 ORDER BY id DESC LIMIT $3", index, fixed_cursor, limit as i64 + 1 @@ -69,7 +80,7 @@ impl Core { ) -> Result<()> { if let Ok(c) = query_as!( Self, - "SELECT * from cores WHERE vindex = $1 AND epoch = $2", + "SELECT * from epochs_cores WHERE vindex = $1 AND epoch_id = $2", vindex, epoch ) @@ -77,7 +88,7 @@ impl Core { .await { query!( - "UPDATE cores SET gas_used=$1,imports=$2,extrinsic_count=$3,extrinsic_size=$4,exports=$5,bundle_size=$6,da_load=$7,popularity=$8 WHERE id = $9", + "UPDATE epochs_cores SET gas_used=$1,imports=$2,extrinsic_count=$3,extrinsic_size=$4,exports=$5,bundle_size=$6,da_load=$7,popularity=$8 WHERE id = $9", c.gas_used + record.gas_used as i64, c.imports + record.imports as i32, c.extrinsic_count + record.extrinsic_count as i32, @@ -91,7 +102,7 @@ impl Core { } else { // insert epoch query!( - "INSERT INTO cores (epoch,vindex,gas_used,imports,extrinsic_count,extrinsic_size,exports,bundle_size,da_load,popularity) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)", + "INSERT INTO epochs_cores (epoch_id,vindex,gas_used,imports,extrinsic_count,extrinsic_size,exports,bundle_size,da_load,popularity) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)", epoch, vindex, record.gas_used as i64, diff --git a/src/models/dispute.rs b/src/models/dispute.rs index 1226363..0c55355 100644 --- a/src/models/dispute.rs +++ b/src/models/dispute.rs @@ -1,13 +1,12 @@ //! TODO: introduce a single type with enum for all dispute related types +use crate::models::hex; use anyhow::Result; use async_graphql::SimpleObject; use score::extrinsic::{Culprit, Fault, Verdict}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::models::hex; - #[derive(SimpleObject, Serialize, Deserialize)] pub struct DisputeVerdict { id: i32, diff --git a/src/models/envelope.rs b/src/models/envelope.rs index 23857d1..6c56d6b 100644 --- a/src/models/envelope.rs +++ b/src/models/envelope.rs @@ -1,11 +1,10 @@ +use crate::models::hex; use anyhow::Result; use async_graphql::SimpleObject; use score::extrinsic::TicketEnvelope; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::models::hex; - #[derive(SimpleObject, Serialize, Deserialize)] pub struct Envelope { id: i32, diff --git a/src/models/epoch.rs b/src/models/epoch.rs index f2e3b1b..c28cf28 100644 --- a/src/models/epoch.rs +++ b/src/models/epoch.rs @@ -1,3 +1,7 @@ +use crate::{ + Manager, + models::{EpochCore, EpochValidator, Validator, hex}, +}; use anyhow::Result; use async_graphql::{ ComplexObject, Context, Result as GraphqlResult, SimpleObject, @@ -7,11 +11,6 @@ use score::{EPOCH_LENGTH, block::header::EpochMark}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::{ - Manager, - models::{Core, Validator, hex}, -}; - #[derive(SimpleObject, Serialize, Deserialize)] #[graphql(complex)] pub struct Epoch { @@ -19,8 +18,6 @@ pub struct Epoch { block: i32, entropy: String, tickets_entropy: String, - validators_ed25519: Vec, - validators_bandersnatches: Vec, blocks: i32, tickets: i32, preimages: i32, @@ -36,15 +33,17 @@ impl Epoch { ctx: &Context<'_>, #[graphql(default = 10, validator(minimum = 1, maximum = 100))] first: Option, #[graphql(desc = "Cursor for pagination")] after: Option, - ) -> GraphqlResult> { + ) -> GraphqlResult> { let limit = first.unwrap_or(10).min(100); let cursor = after.unwrap_or_default().parse::().unwrap_or(0); let pool = &ctx.data::()?.pg; - let data = Validator::list_by_epoch(pool, self.id, limit, cursor).await?; + + let data = EpochValidator::list_by_epoch(pool, self.id, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = data.len() > limit as usize; let items = data.into_iter().take(limit as usize).collect::>(); - let has_next_page = items.len() > limit as usize; - let mut connection = Connection::new(false, has_next_page); + let mut connection = Connection::new(has_prev_page, has_next_page); connection.edges = items .into_iter() .map(|item| Edge::new(item.id.to_string(), item)) @@ -57,15 +56,17 @@ impl Epoch { ctx: &Context<'_>, #[graphql(default = 10, validator(minimum = 1, maximum = 100))] first: Option, #[graphql(desc = "Cursor for pagination")] after: Option, - ) -> GraphqlResult> { + ) -> GraphqlResult> { let limit = first.unwrap_or(10).min(100); let cursor = after.unwrap_or_default().parse::().unwrap_or(0); let pool = &ctx.data::()?.pg; - let data = Core::list_by_epoch(pool, self.id, limit, cursor).await?; + + let data = EpochCore::list_by_epoch(pool, self.id, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = data.len() > limit as usize; let items = data.into_iter().take(limit as usize).collect::>(); - let has_next_page = items.len() > limit as usize; - let mut connection = Connection::new(false, has_next_page); + let mut connection = Connection::new(has_prev_page, has_next_page); connection.edges = items .into_iter() .map(|item| Edge::new(item.id.to_string(), item)) @@ -100,19 +101,12 @@ impl Epoch { } /// FIXME: should accumulate the extrinsic count - #[allow(dead_code)] + //#[allow(dead_code)] pub async fn insert(pool: &PgPool, block: i32, epoch: &EpochMark) -> Result { let entropy = hex(epoch.entropy); let tickets_entropy = hex(epoch.tickets_entropy); - // save validator, and use ed25519 as the primary key - let mut validators_ed25519 = vec![]; - let mut validators_bandersnatches = vec![]; - for validator in epoch.validators { - validators_ed25519.push(hex(validator.ed25519)); - validators_bandersnatches.push(hex(validator.bandersnatch)); - } - let epoch_id = block / EPOCH_LENGTH as i32 + 1; + if query_as!(Self, "SELECT * from epochs WHERE id = $1", epoch_id) .fetch_one(pool) .await @@ -120,25 +114,37 @@ impl Epoch { { // update epoch TODO check epoch is valid query!( - "UPDATE epochs SET block=$1,entropy=$2,tickets_entropy=$3,validators_ed25519=$4,validators_bandersnatches=$5 WHERE id = $6", + "UPDATE epochs SET block=$1,entropy=$2,tickets_entropy=$3 WHERE id = $4", block, entropy, tickets_entropy, - &validators_ed25519, - &validators_bandersnatches, epoch_id - ).execute(pool).await?; + ) + .execute(pool) + .await?; } else { // insert epoch query!( - "INSERT INTO epochs (id, block,entropy,tickets_entropy,validators_ed25519,validators_bandersnatches) VALUES ($1,$2,$3,$4,$5,$6)", + "INSERT INTO epochs (id, block,entropy,tickets_entropy) VALUES ($1,$2,$3,$4)", epoch_id, block, entropy, tickets_entropy, - &validators_ed25519, - &validators_bandersnatches - ).execute(pool).await?; + ) + .execute(pool) + .await?; + } + + // try insert validator + for (vindex, validator) in epoch.validators.iter().enumerate() { + let _ = Validator::insert( + pool, + epoch_id, + &hex(validator.ed25519), + &hex(validator.bandersnatch), + vindex as i32, + ) + .await; } Ok(epoch_id) diff --git a/src/models/guarantee.rs b/src/models/guarantee.rs index 12d7e2d..7f6f362 100644 --- a/src/models/guarantee.rs +++ b/src/models/guarantee.rs @@ -1,11 +1,10 @@ +use crate::models::{WorkResult, hex}; use anyhow::Result; use async_graphql::SimpleObject; use score::extrinsic::ReportGuarantee; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::models::{WorkResult, hex}; - /// ReportGuarantee (WorkReport) #[derive(SimpleObject, Serialize, Deserialize)] pub struct Guarantee { diff --git a/src/models/header.rs b/src/models/header.rs index be9f1ab..0584725 100644 --- a/src/models/header.rs +++ b/src/models/header.rs @@ -1,12 +1,15 @@ +use crate::{ + Manager, + models::{Validator, hex}, +}; use anyhow::Result; -use async_graphql::SimpleObject; +use async_graphql::{ComplexObject, Context, Result as GraphqlResult, SimpleObject}; use score::block::Header as JamHeader; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::models::hex; - #[derive(SimpleObject, Serialize, Deserialize)] +#[graphql(complex)] pub struct Header { pub slot: i32, pub hash: String, @@ -19,6 +22,15 @@ pub struct Header { pub seal: String, pub offenders_mark: Vec, pub current_epoch: i32, + pub author_id: i32, +} + +#[ComplexObject] +impl Header { + async fn author(&self, ctx: &Context<'_>) -> GraphqlResult { + let pool = &ctx.data::()?.pg; + Ok(Validator::get(pool, self.author_id).await?) + } } impl Header { @@ -37,6 +49,27 @@ impl Header { Ok(data) } + /// list all validator's anchoring blocks (DESC) + pub async fn list_by_author( + pool: &PgPool, + author: i32, + limit: i32, + cursor: i32, + ) -> Result> { + let fixed_cursor = if cursor == 0 { i32::MAX } else { cursor }; + let data = query_as!( + Self, + "SELECT * FROM headers WHERE author_id=$1 AND slot<$2 ORDER BY slot DESC LIMIT $3", + author, + fixed_cursor, + limit as i64 + 1 + ) + .fetch_all(pool) + .await?; + + Ok(data) + } + /// NOTE: this will not being used, consider remove it. pub async fn get(pool: &PgPool, slot: i32) -> Result { let data = query_as!(Self, "SELECT * FROM headers WHERE slot=$1", slot) @@ -51,6 +84,7 @@ impl Header { slot: i32, extrinsic_count: i32, current_epoch: i32, + author_id: i32, header: &JamHeader, ) -> Result<()> { // save the block(header) @@ -58,7 +92,7 @@ impl Header { let parent = hex(header.parent); let parent_state_root = hex(header.parent_state_root); let extrinsic_hash = hex(header.extrinsic_hash); - let author_index = header.author_index; + let author_index = header.author_index as i32; let entropy_source = hex(header.entropy_source); let seal = hex(header.seal); @@ -70,18 +104,19 @@ impl Header { .collect::>(); query!( - "INSERT INTO headers (slot,hash,parent,parent_state_root,extrinsic_hash,extrinsic_count,author_index,entropy_source,seal,offenders_mark,current_epoch) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)", + "INSERT INTO headers (slot,hash,parent,parent_state_root,extrinsic_hash,extrinsic_count,author_index,entropy_source,seal,offenders_mark,current_epoch,author_id) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)", slot, block_hash, parent, parent_state_root, extrinsic_hash, extrinsic_count, - author_index as i32, + author_index, entropy_source, seal, &offenders_mark, current_epoch, + author_id ) .execute(pool) .await?; diff --git a/src/models/mod.rs b/src/models/mod.rs index 5b965b5..6a32d54 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -19,7 +19,7 @@ mod work_result; pub use assurance::Assurance; pub use block::Block; -pub use core::Core; +pub use core::EpochCore; pub use dispute::{DisputeCulprit, DisputeFault, DisputeVerdict}; pub use envelope::Envelope; pub use epoch::Epoch; @@ -28,10 +28,16 @@ pub use header::Header; pub use preimage::Preimage; pub use service::Service; pub use ticket::Ticket; -pub use validator::Validator; +pub use validator::{EpochValidator, Validator}; pub use work_result::WorkResult; #[inline] pub fn hex>(bytes: T) -> String { "0x".to_owned() + &hex::encode(bytes) } + +#[inline] +pub fn try_hex(s: &str) -> anyhow::Result { + let bytes = hex::decode(s.trim_start_matches("0x"))?; + Ok(hex(bytes)) +} diff --git a/src/models/preimage.rs b/src/models/preimage.rs index c9e8d90..f7e4e47 100644 --- a/src/models/preimage.rs +++ b/src/models/preimage.rs @@ -1,3 +1,4 @@ +use crate::models::hex; use anyhow::Result; use async_graphql::SimpleObject; use score::extrinsic::Preimage as JamPreimage; @@ -5,8 +6,6 @@ use serde::{Deserialize, Serialize}; use spacejam_crypto::blake2b; use sqlx::PgPool; -use crate::models::hex; - #[derive(SimpleObject, Serialize, Deserialize)] pub struct Preimage { pub id: i32, diff --git a/src/models/service.rs b/src/models/service.rs index 3a83a3f..4ae3b87 100644 --- a/src/models/service.rs +++ b/src/models/service.rs @@ -1,3 +1,7 @@ +use crate::{ + Manager, + models::{Preimage, WorkResult, hex}, +}; use anyhow::Result; use async_graphql::{ ComplexObject, Context, Result as GraphqlResult, SimpleObject, @@ -7,11 +11,6 @@ use score::{ServiceId, service::ServiceData}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::{ - Manager, - models::{Preimage, WorkResult, hex}, -}; - #[derive(SimpleObject, Serialize, Deserialize)] #[graphql(complex)] pub struct Service { @@ -42,11 +41,13 @@ impl Service { let limit = first.unwrap_or(10).min(100); let cursor = after.unwrap_or_default().parse::().unwrap_or(0); let pool = &ctx.data::()?.pg; + let data = Preimage::list_by_service(pool, self.id, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = data.len() > limit as usize; let items = data.into_iter().take(limit as usize).collect::>(); - let has_next_page = items.len() > limit as usize; - let mut connection = Connection::new(false, has_next_page); + let mut connection = Connection::new(has_prev_page, has_next_page); connection.edges = items .into_iter() .map(|item| Edge::new(item.id.to_string(), item)) @@ -63,11 +64,13 @@ impl Service { let limit = first.unwrap_or(10).min(100); let cursor = after.unwrap_or_default().parse::().unwrap_or(0); let pool = &ctx.data::()?.pg; + let data = WorkResult::list_by_service(pool, self.id, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = data.len() > limit as usize; let items = data.into_iter().take(limit as usize).collect::>(); - let has_next_page = items.len() > limit as usize; - let mut connection = Connection::new(false, has_next_page); + let mut connection = Connection::new(has_prev_page, has_next_page); connection.edges = items .into_iter() .map(|item| Edge::new(item.id.to_string(), item)) diff --git a/src/models/ticket.rs b/src/models/ticket.rs index 5f4c889..ec47a4e 100644 --- a/src/models/ticket.rs +++ b/src/models/ticket.rs @@ -1,11 +1,10 @@ +use crate::models::hex; use anyhow::Result; use async_graphql::SimpleObject; use score::extrinsic::TicketBody; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::models::hex; - #[derive(SimpleObject, Serialize, Deserialize)] pub struct Ticket { id: i32, diff --git a/src/models/validator.rs b/src/models/validator.rs index 8725bf7..cecf428 100644 --- a/src/models/validator.rs +++ b/src/models/validator.rs @@ -1,12 +1,133 @@ +use crate::{ + Manager, + models::{Epoch, Header, try_hex}, +}; use anyhow::Result; -use async_graphql::SimpleObject; +use async_graphql::{ + ComplexObject, Context, Result as GraphqlResult, SimpleObject, + connection::{Connection, Edge, EmptyFields}, +}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; #[derive(SimpleObject, Serialize, Deserialize)] +#[graphql(complex)] pub struct Validator { + id: i32, + ed25519: String, + bandersnatch: String, + name: String, + details: String, + software: String, + ip: String, + website: String, + scores: i32, +} + +#[ComplexObject] +impl Validator { + /// List this validator's all epochs data (DESC) + pub async fn epochs( + &self, + ctx: &Context<'_>, + #[graphql(default = 10, validator(minimum = 1, maximum = 100))] first: Option, + #[graphql(desc = "Cursor for pagination")] after: Option, + ) -> GraphqlResult> { + let limit = first.unwrap_or(10).min(100); + let cursor = after.unwrap_or_default().parse::().unwrap_or(0); + let pool = &ctx.data::()?.pg; + + let data = EpochValidator::list_by_validator(pool, self.id, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = data.len() > limit as usize; + let items = data.into_iter().take(limit as usize).collect::>(); + + let mut connection = Connection::new(has_prev_page, has_next_page); + connection.edges = items + .into_iter() + .map(|item| Edge::new(item.id.to_string(), item)) + .collect(); + Ok(connection) + } + + /// List this validator's all anchor blocks (DESC) + pub async fn blocks( + &self, + ctx: &Context<'_>, + #[graphql(default = 10, validator(minimum = 1, maximum = 100))] first: Option, + #[graphql(desc = "Cursor for pagination")] after: Option, + ) -> GraphqlResult> { + let limit = first.unwrap_or(10).min(100); + let cursor = after.unwrap_or_default().parse::().unwrap_or(0); + let pool = &ctx.data::()?.pg; + + let data = Header::list_by_author(pool, self.id, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = data.len() > limit as usize; + let items = data.into_iter().take(limit as usize).collect::>(); + + let mut connection = Connection::new(has_prev_page, has_next_page); + connection.edges = items + .into_iter() + .map(|item| Edge::new(item.slot.to_string(), item)) + .collect(); + Ok(connection) + } +} + +impl Validator { + pub async fn get(pool: &PgPool, id: i32) -> Result { + let data = query_as!(Self, "SELECT * FROM validators WHERE id = $1", id) + .fetch_one(pool) + .await?; + + Ok(data) + } + + pub async fn get_by_ed25519(pool: &PgPool, hex: &str) -> Result { + let hex = try_hex(hex)?; + let data = query_as!(Self, "SELECT * FROM validators WHERE ed25519 = $1", hex) + .fetch_one(pool) + .await?; + + Ok(data) + } + + pub async fn insert( + pool: &PgPool, + epoch: i32, + ed25519: &str, + bandersnatch: &str, + vindex: i32, + ) -> Result<()> { + // create validator + let validator = if let Ok(validator) = + query_as!(Self, "SELECT * FROM validators WHERE ed25519=$1", ed25519) + .fetch_one(pool) + .await + { + validator.id + } else { + query_scalar!( + "INSERT INTO validators (ed25519,bandersnatch) VALUES ($1, $2) RETURNING id", + ed25519, + bandersnatch + ) + .fetch_one(pool) + .await? + }; + + // create validators with epoch + EpochValidator::insert(pool, epoch, validator, vindex).await + } +} + +#[derive(SimpleObject, Serialize, Deserialize)] +#[graphql(complex)] +pub struct EpochValidator { pub id: i32, - epoch: i32, + epoch_id: i32, + validator_id: i32, vindex: i32, blocks: i32, tickets: i32, @@ -15,7 +136,22 @@ pub struct Validator { assurances: i32, } -impl Validator { +#[ComplexObject] +impl EpochValidator { + /// Get the Epoch + pub async fn epoch(&self, ctx: &Context<'_>) -> GraphqlResult { + let pool = &ctx.data::()?.pg; + Ok(Epoch::get(pool, self.epoch_id).await?) + } + + /// Get the Validator + pub async fn validator(&self, ctx: &Context<'_>) -> GraphqlResult { + let pool = &ctx.data::()?.pg; + Ok(Validator::get(pool, self.validator_id).await?) + } +} + +impl EpochValidator { /// List all validators in the epoch (ASC) pub async fn list_by_epoch( pool: &PgPool, @@ -25,7 +161,7 @@ impl Validator { ) -> Result> { let data = query_as!( Self, - "SELECT * FROM validators WHERE epoch=$1 AND id>$2 ORDER BY id ASC LIMIT $3", + "SELECT * FROM epochs_validators WHERE epoch_id=$1 AND id>$2 ORDER BY id ASC LIMIT $3", epoch, cursor, limit as i64 + 1 @@ -37,17 +173,17 @@ impl Validator { } /// list all validator's epoch statistics (DESC) - pub async fn list_by_index( + pub async fn list_by_validator( pool: &PgPool, - index: i32, + validator: i32, limit: i32, cursor: i32, ) -> Result> { let fixed_cursor = if cursor == 0 { i32::MAX } else { cursor }; let data = query_as!( Self, - "SELECT * FROM validators WHERE vindex=$1 AND id<$2 ORDER BY id DESC LIMIT $3", - index, + "SELECT * FROM epochs_validators WHERE validator_id=$1 AND id<$2 ORDER BY id DESC LIMIT $3", + validator, fixed_cursor, limit as i64 + 1 ) @@ -57,6 +193,38 @@ impl Validator { Ok(data) } + pub async fn insert(pool: &PgPool, epoch: i32, validator: i32, vindex: i32) -> Result<()> { + if query_as!( + Self, + "SELECT * FROM epochs_validators WHERE epoch_id=$1 AND validator_id=$2", + epoch, + validator + ) + .fetch_one(pool) + .await + .is_ok() + { + tracing::warn!("already had epochs_validators, epoch: {epoch}, validator: {validator}"); + return Ok(()); + } + + query!( + "INSERT INTO epochs_validators (epoch_id,validator_id,vindex,blocks,tickets,preimages,guarantees,assurances) VALUES ($1,$2,$3,$4,$5,$6,$7,$8)", + epoch, + validator, + vindex, + 0, + 0, + 0, + 0, + 0 + ) + .execute(pool) + .await?; + + Ok(()) + } + pub async fn new_block( pool: &PgPool, epoch: i32, @@ -65,16 +233,20 @@ impl Validator { preimages: i32, guarantees: i32, assurances: i32, - ) -> Result<()> { - if let Ok(validators) = query_as!(Self, "SELECT * FROM validators WHERE epoch=$1", epoch) - .fetch_all(pool) - .await + ) -> Result { + if let Ok(validators) = query_as!( + Self, + "SELECT * FROM epochs_validators WHERE epoch_id=$1", + epoch + ) + .fetch_all(pool) + .await { for v in validators { if v.vindex == vindex { // do update query!( - "UPDATE validators SET blocks=$1,tickets=$2,preimages=$3,guarantees=$4,assurances=$5 WHERE id=$6", + "UPDATE epochs_validators SET blocks=$1,tickets=$2,preimages=$3,guarantees=$4,assurances=$5 WHERE id=$6", v.blocks + 1, v.tickets + tickets, v.preimages + preimages, @@ -85,24 +257,12 @@ impl Validator { .execute(pool) .await?; - return Ok(()); + return Ok(v.validator_id); } } } - query!( - "INSERT INTO validators (epoch,vindex,blocks,tickets,preimages,guarantees,assurances) VALUES ($1,$2,$3,$4,$5,$6,$7)", - epoch, - vindex, - 1, - tickets, - preimages, - guarantees, - assurances - ) - .execute(pool) - .await?; - - Ok(()) + tracing::warn!("missed epochs_validators, epoch: {epoch}, vindex: {vindex}"); + Ok(0) } } diff --git a/src/models/work_result.rs b/src/models/work_result.rs index 90ea626..f6e4891 100644 --- a/src/models/work_result.rs +++ b/src/models/work_result.rs @@ -1,11 +1,10 @@ +use crate::models::hex; use anyhow::Result; use async_graphql::SimpleObject; use score::service::{WorkExecResult, WorkResult as JamWorkResult}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use crate::models::hex; - #[derive(SimpleObject, Serialize, Deserialize)] pub struct WorkResult { /// The key of the service diff --git a/src/schema/root.rs b/src/schema/root.rs index 404ef69..819f439 100644 --- a/src/schema/root.rs +++ b/src/schema/root.rs @@ -3,7 +3,7 @@ use crate::{ Manager, manager::Spacejam, - models::{Block, Core, Epoch, Header, Service, Validator}, + models::{Block, Epoch, EpochCore, Header, Service, Validator}, }; use async_graphql::{ Context, Object, Result, @@ -32,10 +32,11 @@ impl QueryRoot { let pool = &ctx.data::()?.pg; let headers = Header::list(pool, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = headers.len() > limit as usize; let items = headers.into_iter().take(limit as usize).collect::>(); - let has_next_page = items.len() > limit as usize; - let mut connection = Connection::new(false, has_next_page); + let mut connection = Connection::new(has_prev_page, has_next_page); connection.edges = items .into_iter() .map(|item| Edge::new(item.slot.to_string(), item)) @@ -52,8 +53,10 @@ impl QueryRoot { } /// Get the block data from the database. - async fn block(&self, _ctx: &Context<'_>, slot: i32) -> Result { - Ok(Block { slot }) + async fn block(&self, ctx: &Context<'_>, slot: i32) -> Result> { + let pool = &ctx.data::()?.pg; + let block = Block::get(pool, slot).await.ok(); + Ok(block) } /// Get the epoch by id @@ -63,28 +66,23 @@ impl QueryRoot { Ok(epoch) } - /// Get the validator with all epoch statistics + /// Get the epoch by id/ed25519 async fn validator( &self, ctx: &Context<'_>, - index: i32, - #[graphql(default = 10, validator(minimum = 1, maximum = 100))] first: Option, - #[graphql(desc = "Cursor for pagination")] after: Option, - ) -> Result> { - let limit = first.unwrap_or(10).min(100); - let cursor = after.unwrap_or_default().parse::().unwrap_or(0); + id: Option, + ed25519: Option, + ) -> Result> { let pool = &ctx.data::()?.pg; + if let Some(id) = id { + return Ok(Validator::get(pool, id).await.ok()); + } - let vs = Validator::list_by_index(pool, index, limit, cursor).await?; - let items = vs.into_iter().take(limit as usize).collect::>(); + if let Some(ed25519) = ed25519 { + return Ok(Validator::get_by_ed25519(pool, &ed25519).await.ok()); + } - let has_next_page = items.len() > limit as usize; - let mut connection = Connection::new(false, has_next_page); - connection.edges = items - .into_iter() - .map(|item| Edge::new(item.id.to_string(), item)) - .collect(); - Ok(connection) + Ok(None) } /// Get the core with all epoch statistics @@ -94,16 +92,17 @@ impl QueryRoot { index: i32, #[graphql(default = 10, validator(minimum = 1, maximum = 100))] first: Option, #[graphql(desc = "Cursor for pagination")] after: Option, - ) -> Result> { + ) -> Result> { let limit = first.unwrap_or(10).min(100); let cursor = after.unwrap_or_default().parse::().unwrap_or(0); let pool = &ctx.data::()?.pg; - let cores = Core::list_by_index(pool, index, limit, cursor).await?; + let cores = EpochCore::list_by_index(pool, index, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = cores.len() > limit as usize; let items = cores.into_iter().take(limit as usize).collect::>(); - let has_next_page = items.len() > limit as usize; - let mut connection = Connection::new(false, has_next_page); + let mut connection = Connection::new(has_prev_page, has_next_page); connection.edges = items .into_iter() .map(|item| Edge::new(item.id.to_string(), item)) @@ -123,13 +122,14 @@ impl QueryRoot { let pool = &ctx.data::()?.pg; let services = Service::list(pool, limit, cursor).await?; + let has_prev_page = cursor != 0; + let has_next_page = services.len() > limit as usize; let items = services .into_iter() .take(limit as usize) .collect::>(); - let has_next_page = items.len() > limit as usize; - let mut connection = Connection::new(false, has_next_page); + let mut connection = Connection::new(has_prev_page, has_next_page); connection.edges = items .into_iter() .map(|item| Edge::new(item.id.to_string(), item))