diff --git a/Cargo.lock b/Cargo.lock index bdbfa407da9..acc05e76643 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -944,6 +944,7 @@ version = "0.1.0" dependencies = [ "bp-messages", "bp-rialto", + "bp-runtime", "frame-support", "hex", "hex-literal", @@ -970,6 +971,7 @@ name = "bp-rialto-parachain" version = "0.1.0" dependencies = [ "bp-messages", + "bp-polkadot-core", "bp-runtime", "frame-support", "frame-system", @@ -12401,6 +12403,7 @@ dependencies = [ "bp-millau", "bp-parachains", "bp-polkadot-core", + "bp-relayers", "bp-rialto", "bp-rococo", "bp-runtime", @@ -12411,6 +12414,7 @@ dependencies = [ "frame-support", "frame-system", "futures", + "hex", "log", "messages-relay", "num-traits", diff --git a/bin/millau/runtime/src/lib.rs b/bin/millau/runtime/src/lib.rs index dbff7f5940c..6c401b9a94b 100644 --- a/bin/millau/runtime/src/lib.rs +++ b/bin/millau/runtime/src/lib.rs @@ -1001,21 +1001,6 @@ impl_runtime_apis! { use rialto_messages::WithRialtoMessageBridge; impl MessagesConfig for Runtime { - fn bridged_relayer_id() -> Self::InboundRelayer { - [0u8; 32].into() - } - - fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { - pallet_bridge_relayers::Pallet::::relayer_reward(relayer, &Self::bench_lane_id()).is_some() - } - - fn endow_account(account: &Self::AccountId) { - pallet_balances::Pallet::::make_free_balance_be( - account, - Balance::MAX / 100, - ); - } - fn prepare_message_proof( params: MessageProofParams, ) -> (rialto_messages::FromRialtoMessagesProof, Weight) { @@ -1032,8 +1017,8 @@ impl_runtime_apis! { ) } - fn is_message_dispatched(_nonce: bp_messages::MessageNonce) -> bool { - true + fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { + pallet_bridge_relayers::Pallet::::relayer_reward(relayer, &Self::bench_lane_id()).is_some() } } diff --git a/bin/rialto-parachain/runtime/Cargo.toml b/bin/rialto-parachain/runtime/Cargo.toml index 2327a864c2c..b91e1cd2751 100644 --- a/bin/rialto-parachain/runtime/Cargo.toml +++ b/bin/rialto-parachain/runtime/Cargo.toml @@ -75,6 +75,9 @@ xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +[dev-dependencies] +bridge-runtime-common = { path = "../../runtime-common", features = ["integrity-test"] } + [features] default = ['std'] runtime-benchmarks = [ diff --git a/bin/rialto-parachain/runtime/src/lib.rs b/bin/rialto-parachain/runtime/src/lib.rs index b9f4c236d86..5ad8506acbf 100644 --- a/bin/rialto-parachain/runtime/src/lib.rs +++ b/bin/rialto-parachain/runtime/src/lib.rs @@ -848,8 +848,11 @@ mod tests { LaneId, MessageKey, }; use bp_runtime::messages::MessageDispatchResult; - use bridge_runtime_common::messages::target::FromBridgedChainMessageDispatch; + use bridge_runtime_common::{ + integrity::check_additional_signed, messages::target::FromBridgedChainMessageDispatch, + }; use codec::Encode; + use sp_runtime::generic::Era; fn new_test_ext() -> sp_io::TestExternalities { sp_io::TestExternalities::new( @@ -909,4 +912,25 @@ mod tests { ); }) } + + #[test] + fn ensure_signed_extension_definition_is_correct() { + let payload: SignedExtra = ( + frame_system::CheckNonZeroSender::new(), + frame_system::CheckSpecVersion::new(), + frame_system::CheckTxVersion::new(), + frame_system::CheckGenesis::new(), + frame_system::CheckEra::from(Era::Immortal), + frame_system::CheckNonce::from(10), + frame_system::CheckWeight::new(), + pallet_transaction_payment::ChargeTransactionPayment::from(10), + ); + let indirect_payload = bp_rialto_parachain::SignedExtension::new( + ((), (), (), (), Era::Immortal, 10.into(), (), 10.into()), + None, + ); + assert_eq!(payload.encode(), indirect_payload.encode()); + + check_additional_signed::(); + } } diff --git a/bin/runtime-common/src/integrity.rs b/bin/runtime-common/src/integrity.rs index 9c4553ad136..e8e3e7f87cc 100644 --- a/bin/runtime-common/src/integrity.rs +++ b/bin/runtime-common/src/integrity.rs @@ -26,6 +26,7 @@ use bp_runtime::{Chain, ChainId}; use codec::Encode; use frame_support::{storage::generator::StorageValue, traits::Get}; use frame_system::limits; +use sp_runtime::traits::SignedExtension; /// Macro that ensures that the runtime configuration and chain primitives crate are sharing /// the same types (index, block number, hash, hasher, account id and header). @@ -319,3 +320,15 @@ pub fn check_message_lane_weights( this_chain_max_unconfirmed_messages, ); } + +/// Check that the `AdditionalSigned` type of a wrapped runtime is the same as the one of the +/// corresponding actual runtime. +/// +/// This method doesn't perform any `assert`. If the condition is not true it will generate a +/// compile-time error. +pub fn check_additional_signed() +where + SignedExt: SignedExtension, + IndirectSignedExt: SignedExtension, +{ +} diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json index ecb06074d7f..4f134914f70 100644 --- a/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json +++ b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json @@ -8,14 +8,22 @@ "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, "type": "dashboard" } ] }, "editable": true, + "fiscalYearStartMonth": 0, "gnetId": null, "graphTooltip": 0, "links": [], + "liveNow": false, "panels": [ { "alert": { @@ -66,29 +74,6 @@ "type": "last" }, "type": "query" - }, - { - "evaluator": { - "params": [ - 1000 - ], - "type": "lt" - }, - "operator": { - "type": "or" - }, - "query": { - "params": [ - "C", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" } ], "executionErrorState": "alerting", @@ -104,19 +89,13 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 16 + "y": 0 }, "hiddenSeries": false, "id": 8, @@ -132,8 +111,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -161,7 +143,8 @@ "fill": true, "line": true, "op": "lt", - "value": 1000 + "value": 1000, + "visible": true } ], "timeFrom": null, @@ -253,29 +236,6 @@ "type": "last" }, "type": "query" - }, - { - "evaluator": { - "params": [ - 1000 - ], - "type": "lt" - }, - "operator": { - "type": "or" - }, - "query": { - "params": [ - "C", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" } ], "executionErrorState": "alerting", @@ -291,19 +251,13 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, - "y": 16 + "y": 0 }, "hiddenSeries": false, "id": 9, @@ -319,8 +273,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -348,7 +305,8 @@ "fill": true, "line": true, "op": "lt", - "value": 1000 + "value": 1000, + "visible": true } ], "timeFrom": null, @@ -432,19 +390,13 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 24 + "y": 8 }, "hiddenSeries": false, "id": 11, @@ -460,8 +412,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -483,7 +438,8 @@ "fill": true, "line": true, "op": "gt", - "value": 0 + "value": 0, + "visible": true } ], "timeFrom": null, @@ -567,19 +523,13 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, - "y": 24 + "y": 8 }, "hiddenSeries": false, "id": 12, @@ -595,8 +545,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -618,7 +571,8 @@ "fill": true, "line": true, "op": "gt", - "value": 0 + "value": 0, + "visible": true } ], "timeFrom": null, @@ -660,108 +614,10 @@ "align": false, "alignLevel": null } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 32 - }, - "hiddenSeries": false, - "id": 14, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "Millau_to_Rialto_MessageLane_00000000_unprofitable_delivery_transactions", - "interval": "", - "legendFormat": "Millau -> Rialto, lane 00000000", - "refId": "A" - }, - { - "expr": "Rialto_to_Millau_MessageLane_00000000_unprofitable_delivery_transactions", - "interval": "", - "legendFormat": "Rialto -> Millau, lane 00000000", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Count of unprofitable message delivery transactions", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } } ], "refresh": "10s", - "schemaVersion": 26, + "schemaVersion": 32, "style": "dark", "tags": [], "templating": { diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json index 0da5b8cb4dc..b54bf1b48c5 100644 --- a/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json +++ b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json @@ -8,14 +8,22 @@ "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, "type": "dashboard" } ] }, "editable": true, + "fiscalYearStartMonth": 0, "gnetId": null, "graphTooltip": 0, "links": [], + "liveNow": false, "panels": [ { "alert": { @@ -43,52 +51,6 @@ "type": "last" }, "type": "query" - }, - { - "evaluator": { - "params": [ - 1000 - ], - "type": "lt" - }, - "operator": { - "type": "or" - }, - "query": { - "params": [ - "B", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - }, - { - "evaluator": { - "params": [ - 1000 - ], - "type": "lt" - }, - "operator": { - "type": "or" - }, - "query": { - "params": [ - "C", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" } ], "executionErrorState": "alerting", @@ -104,19 +66,13 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 16 + "y": 0 }, "hiddenSeries": false, "id": 10, @@ -132,8 +88,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -143,16 +102,29 @@ "steppedLine": false, "targets": [ { - "expr": "at_RialtoParachain_relay_MillauHeaders_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "exemplar": true, + "expr": "at_RialtoParachain_relay_MillauMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, "interval": "", - "legendFormat": "With-Millau headers relay account balance", + "legendFormat": "With-Millau relay account balance", "refId": "A" }, { - "expr": "at_RialtoParachain_relay_MillauMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "exemplar": true, + "expr": "at_RialtoParachain_relay_MillauMessages_reward_for_lane_00000000_with_Millau{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "hide": false, + "instant": false, "interval": "", - "legendFormat": "With-Millau messages relay account balance", + "legendFormat": "With-Millau relay account reward", "refId": "B" + }, + { + "exemplar": true, + "expr": "at_RialtoParachain_relay_MillauMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"} + at_RialtoParachain_relay_MillauMessages_reward_for_lane_00000000_with_Millau{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "hide": false, + "interval": "", + "legendFormat": "With-Millau relay account total balance (balance + reward)", + "refId": "C" } ], "thresholds": [ @@ -161,7 +133,8 @@ "fill": true, "line": true, "op": "lt", - "value": 1000 + "value": 1000, + "visible": true } ], "timeFrom": null, @@ -230,52 +203,6 @@ "type": "last" }, "type": "query" - }, - { - "evaluator": { - "params": [ - 1000 - ], - "type": "lt" - }, - "operator": { - "type": "or" - }, - "query": { - "params": [ - "B", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" - }, - { - "evaluator": { - "params": [ - 1000 - ], - "type": "lt" - }, - "operator": { - "type": "or" - }, - "query": { - "params": [ - "C", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "last" - }, - "type": "query" } ], "executionErrorState": "alerting", @@ -291,19 +218,13 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, - "y": 16 + "y": 0 }, "hiddenSeries": false, "id": 12, @@ -319,8 +240,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -330,21 +254,26 @@ "steppedLine": false, "targets": [ { - "expr": "at_Millau_relay_RialtoHeaders_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "exemplar": true, + "expr": "at_Millau_relay_RialtoParachainMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", "interval": "", - "legendFormat": "With-Rialto headers relay account balance", + "legendFormat": "With-Rialto relay account balance", "refId": "A" }, { - "expr": "at_Millau_relay_RialtoParachainMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "exemplar": true, + "expr": "at_Millau_relay_RialtoParachainMessages_reward_for_lane_00000000_with_RialtoParachain{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "hide": false, "interval": "", - "legendFormat": "With-RialtoParachain messages relay account balance", + "legendFormat": "With-Rialto relay account reward", "refId": "B" }, { - "expr": "at_Millau_relay_RialtoParachains_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "exemplar": true, + "expr": "at_Millau_relay_RialtoParachainMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"} + \nat_Millau_relay_RialtoParachainMessages_reward_for_lane_00000000_with_RialtoParachain{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "hide": false, "interval": "", - "legendFormat": "With-Rialto parachains relay account balance", + "legendFormat": "With-Rialto relay account total balance (balance + reward)", "refId": "C" } ], @@ -354,7 +283,8 @@ "fill": true, "line": true, "op": "lt", - "value": 1000 + "value": 1000, + "visible": true } ], "timeFrom": null, @@ -438,19 +368,13 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 24 + "y": 8 }, "hiddenSeries": false, "id": 14, @@ -466,8 +390,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -490,7 +417,8 @@ "fill": true, "line": true, "op": "gt", - "value": 0 + "value": 0, + "visible": true } ], "timeFrom": null, @@ -574,19 +502,13 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, - "y": 24 + "y": 8 }, "hiddenSeries": false, "id": 16, @@ -602,8 +524,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -625,7 +550,8 @@ "fill": true, "line": true, "op": "gt", - "value": 0 + "value": 0, + "visible": true } ], "timeFrom": null, @@ -670,7 +596,7 @@ } ], "refresh": "5s", - "schemaVersion": 26, + "schemaVersion": 32, "style": "dark", "tags": [], "templating": { diff --git a/docs/high-level-overview.md b/docs/high-level-overview.md index 5a76347ce4f..f2806719256 100644 --- a/docs/high-level-overview.md +++ b/docs/high-level-overview.md @@ -41,7 +41,7 @@ proofs are called mandatory in the pallet and relayer pays no fee for such heade The pallet does not require all headers to be imported or provided. The relayer itself chooses which headers he wants to submit (with the exception of mandatory headers). -More: [code](../modules/grandpa/). +More: [pallet level documentation and code](../modules/grandpa/). ### Bridge Parachains Finality Pallet @@ -60,7 +60,7 @@ The pallet may track multiple parachains at once and those parachains may use di parachain header decoding never happens at the pallet level. For maintaining the headers order, the pallet uses relay chain header number. -More: [code](../modules/parachains/). +More: [pallet level documentation and code](../modules/parachains/). ### Bridge Messages Pallet @@ -91,14 +91,14 @@ pallet, in this case, depends on one of the finality pallets. The messages are X XCM executor to dispatch them on receival. You may find more info in [Polkadot <> Kusama Bridge](./polkadot-kusama-bridge-overview.md) document. -More: [code](../modules/messages/). +More: [pallet level documentation and code](../modules/messages/). ### Bridge Relayers Pallet The pallet is quite simple. It just registers relayer rewards and has an entrypoint to collect them. When the rewards are registered and the reward amount is configured outside of the pallet. -More: [code](../modules/relayers/). +More: [pallet level documentation and code](../modules/relayers/). ## Offchain Components diff --git a/modules/beefy/Cargo.toml b/modules/beefy/Cargo.toml index 2dca89d82e5..1908bd50c8a 100644 --- a/modules/beefy/Cargo.toml +++ b/modules/beefy/Cargo.toml @@ -48,3 +48,7 @@ std = [ "sp-runtime/std", "sp-std/std", ] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/grandpa/Cargo.toml b/modules/grandpa/Cargo.toml index 45f314a0bbd..9e260a33537 100644 --- a/modules/grandpa/Cargo.toml +++ b/modules/grandpa/Cargo.toml @@ -57,3 +57,7 @@ runtime-benchmarks = [ "bp-test-utils", "frame-benchmarking/runtime-benchmarks", ] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/messages/Cargo.toml b/modules/messages/Cargo.toml index 0c2fecb0be3..afa8b92b228 100644 --- a/modules/messages/Cargo.toml +++ b/modules/messages/Cargo.toml @@ -50,3 +50,7 @@ std = [ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", ] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/messages/src/benchmarking.rs b/modules/messages/src/benchmarking.rs index 62dd1d60caf..a89cb3a8ef0 100644 --- a/modules/messages/src/benchmarking.rs +++ b/modules/messages/src/benchmarking.rs @@ -27,9 +27,11 @@ use bp_messages::{ UnrewardedRelayersState, }; use bp_runtime::StorageProofSize; +use codec::Decode; use frame_benchmarking::{account, benchmarks_instance_pallet}; use frame_support::weights::Weight; use frame_system::RawOrigin; +use sp_runtime::traits::TrailingZeroInput; use sp_std::{ops::RangeInclusive, prelude::*}; const SEED: u32 = 0; @@ -64,15 +66,26 @@ pub struct MessageDeliveryProofParams { /// Trait that must be implemented by runtime. pub trait Config: crate::Config { /// Lane id to use in benchmarks. + /// + /// By default, lane 00000000 is used. fn bench_lane_id() -> LaneId { - Default::default() + LaneId([0, 0, 0, 0]) } + /// Return id of relayer account at the bridged chain. - fn bridged_relayer_id() -> Self::InboundRelayer; - /// Returns true if given relayer has been rewarded for some of its actions. - fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool; - /// Create given account and give it enough balance for test purposes. - fn endow_account(account: &Self::AccountId); + /// + /// By default, zero account is returned. + fn bridged_relayer_id() -> Self::InboundRelayer { + Self::InboundRelayer::decode(&mut TrailingZeroInput::zeroes()).unwrap() + } + + /// Create given account and give it enough balance for test purposes. Used to create + /// relayer account at the target chain. Is strictly necessary when your rewards scheme + /// assumes that the relayer account must exist. + /// + /// Does nothing by default. + fn endow_account(_account: &Self::AccountId) {} + /// Prepare messages proof to receive by the module. fn prepare_message_proof( params: MessageProofParams, @@ -81,8 +94,20 @@ pub trait Config: crate::Config { fn prepare_message_delivery_proof( params: MessageDeliveryProofParams, ) -> >::MessagesDeliveryProof; + /// Returns true if message has been dispatched (either successfully or not). - fn is_message_dispatched(nonce: MessageNonce) -> bool; + /// + /// We assume that messages have near-zero dispatch weight, so most of times it + /// is hard to determine whether messages has been dispatched or not. For example, + /// XCM message can be a call that leaves entry in `frame_system::Events` vector, + /// but not all XCM messages do that and we don't want to include weight of this + /// action to the base weight of message delivery. Hence, the default `true` return + /// value. + fn is_message_dispatched(_nonce: MessageNonce) -> bool { + true + } + /// Returns true if given relayer has been rewarded for some of its actions. + fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool; } benchmarks_instance_pallet! { diff --git a/modules/parachains/Cargo.toml b/modules/parachains/Cargo.toml index 3c3ad95fe34..c25956248d0 100644 --- a/modules/parachains/Cargo.toml +++ b/modules/parachains/Cargo.toml @@ -54,3 +54,7 @@ std = [ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", ] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/relayers/Cargo.toml b/modules/relayers/Cargo.toml index 9c071238363..c7ea1e544f2 100644 --- a/modules/relayers/Cargo.toml +++ b/modules/relayers/Cargo.toml @@ -15,6 +15,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" bp-messages = { path = "../../primitives/messages", default-features = false } bp-relayers = { path = "../../primitives/relayers", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Dependencies @@ -37,6 +38,7 @@ default = ["std"] std = [ "bp-messages/std", "bp-relayers/std", + "bp-runtime/std", "codec/std", "frame-support/std", "frame-system/std", @@ -49,3 +51,7 @@ std = [ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", ] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/relayers/README.md b/modules/relayers/README.md new file mode 100644 index 00000000000..656200f4486 --- /dev/null +++ b/modules/relayers/README.md @@ -0,0 +1,14 @@ +# Bridge Relayers Pallet + +The pallet serves as a storage for pending bridge relayer rewards. Any runtime component may register reward +to some relayer for doing some useful job at some messages lane. Later, the relayer may claim its rewards +using the `claim_rewards` call. + +The reward payment procedure is abstracted from the pallet code. One of possible implementations, is the +[`PayLaneRewardFromAccount`](../../primitives/relayers/src/lib.rs), which just does a `Currency::transfer` +call to relayer account from the relayer-rewards account, determined by the message lane id. + +We have two examples of how this pallet is used in production. Rewards are registered at the target chain to +compensate fees of message delivery transactions (and linked finality delivery calls). At the source chain, rewards +are registered during delivery confirmation transactions. You may find more information about that in the +[Kusama <> Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md) documentation. diff --git a/modules/relayers/src/lib.rs b/modules/relayers/src/lib.rs index b28d17cf5a4..7132914a4ae 100644 --- a/modules/relayers/src/lib.rs +++ b/modules/relayers/src/lib.rs @@ -21,7 +21,8 @@ #![warn(missing_docs)] use bp_messages::LaneId; -use bp_relayers::PaymentProcedure; +use bp_relayers::{PaymentProcedure, RelayerRewardsKeyProvider}; +use bp_runtime::StorageDoubleMapKeyProvider; use frame_support::sp_runtime::Saturating; use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero}; use sp_std::marker::PhantomData; @@ -46,6 +47,10 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + /// `RelayerRewardsKeyProvider` for given configuration. + type RelayerRewardsKeyProviderOf = + RelayerRewardsKeyProvider<::AccountId, ::Reward>; + #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. @@ -146,11 +151,11 @@ pub mod pallet { #[pallet::getter(fn relayer_reward)] pub type RelayerRewards = StorageDoubleMap< _, - Blake2_128Concat, - T::AccountId, - Identity, - LaneId, - T::Reward, + as StorageDoubleMapKeyProvider>::Hasher1, + as StorageDoubleMapKeyProvider>::Key1, + as StorageDoubleMapKeyProvider>::Hasher2, + as StorageDoubleMapKeyProvider>::Key2, + as StorageDoubleMapKeyProvider>::Value, OptionQuery, >; } diff --git a/modules/shift-session-manager/Cargo.toml b/modules/shift-session-manager/Cargo.toml index 5dae3e00fd3..504adfae416 100644 --- a/modules/shift-session-manager/Cargo.toml +++ b/modules/shift-session-manager/Cargo.toml @@ -33,3 +33,7 @@ std = [ "sp-staking/std", "sp-std/std", ] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/shift-session-manager/README.md b/modules/shift-session-manager/README.md new file mode 100644 index 00000000000..8dfbfd416e3 --- /dev/null +++ b/modules/shift-session-manager/README.md @@ -0,0 +1,10 @@ +# Shift Session Manager Pallet + +**THIS PALLET IS NOT INTENDED TO BE USED IN PRODUCTION** + +The pallet does not provide any calls or runtime storage entries. It only provides implementation of the +`pallet_session::SessionManager`. This implementation, starting from session `3` selects two thirds of initial +validators and changes the set on every session. We are using it at our testnets ([Rialto](../../bin/rialto/) and +[Millau](../../bin/millau/)) to be sure that the set changes every session. On well-known production chains +(like Kusama and Polkadot) the alternative is the set of [nPoS](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html) +pallets, which selects validators, based on their nominations. diff --git a/primitives/chain-bridge-hub-cumulus/src/lib.rs b/primitives/chain-bridge-hub-cumulus/src/lib.rs index e33131ff8a2..286fbdbebc3 100644 --- a/primitives/chain-bridge-hub-cumulus/src/lib.rs +++ b/primitives/chain-bridge-hub-cumulus/src/lib.rs @@ -18,9 +18,9 @@ use bp_messages::*; pub use bp_polkadot_core::{ - AccountId, AccountInfoStorageMapKeyProvider, AccountPublic, Balance, BlockNumber, - BridgeSignedExtension, Hash, Hasher, Hashing, Header, Index, Nonce, Perbill, - PolkadotSignedExtension, Signature, SignedBlock, UncheckedExtrinsic, TX_EXTRA_BYTES, + AccountId, AccountInfoStorageMapKeyProvider, AccountPublic, Balance, BlockNumber, Hash, Hasher, + Hashing, Header, Index, Nonce, Perbill, PolkadotSignedExtension, Signature, SignedBlock, + UncheckedExtrinsic, TX_EXTRA_BYTES, }; use frame_support::{ dispatch::DispatchClass, @@ -86,6 +86,8 @@ pub type AccountSigner = MultiSigner; /// The address format for describing accounts. pub type Address = MultiAddress; +pub use bp_polkadot_core::BridgeSignedExtension as SignedExtension; + // Note about selecting values of two following constants: // // Normal transactions have limit of 75% of 1/2 second weight for Cumulus parachains. Let's keep diff --git a/primitives/chain-rialto-parachain/Cargo.toml b/primitives/chain-rialto-parachain/Cargo.toml index a15c4092957..ed7c5c07960 100644 --- a/primitives/chain-rialto-parachain/Cargo.toml +++ b/primitives/chain-rialto-parachain/Cargo.toml @@ -11,6 +11,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" # Bridge Dependencies bp-messages = { path = "../messages", default-features = false } +bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies diff --git a/primitives/chain-rialto-parachain/src/lib.rs b/primitives/chain-rialto-parachain/src/lib.rs index 8a98ffe7061..d39fe253783 100644 --- a/primitives/chain-rialto-parachain/src/lib.rs +++ b/primitives/chain-rialto-parachain/src/lib.rs @@ -133,6 +133,8 @@ impl Parachain for RialtoParachain { const PARACHAIN_ID: u32 = RIALTO_PARACHAIN_ID; } +pub use bp_polkadot_core::DefaultSignedExtension as SignedExtension; + frame_support::parameter_types! { pub BlockLength: limits::BlockLength = limits::BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); diff --git a/primitives/polkadot-core/src/lib.rs b/primitives/polkadot-core/src/lib.rs index 3d4b72fccb9..d5a9b5de817 100644 --- a/primitives/polkadot-core/src/lib.rs +++ b/primitives/polkadot-core/src/lib.rs @@ -266,7 +266,7 @@ impl PolkadotSignedExtension for DefaultSignedExtension { (), // Check weight tip.into(), // transaction payment / tip (compact encoding) ), - ( + Some(( (), spec_version, transaction_version, @@ -275,7 +275,7 @@ impl PolkadotSignedExtension for DefaultSignedExtension { (), (), (), - ), + )), ) } @@ -326,7 +326,7 @@ impl PolkadotSignedExtension for BridgeSignedExtension { tip.into(), // transaction payment / tip (compact encoding) (), // bridge reject obsolete headers and msgs ), - ( + Some(( (), spec_version, transaction_version, @@ -336,7 +336,7 @@ impl PolkadotSignedExtension for BridgeSignedExtension { (), (), (), - ), + )), ) } diff --git a/primitives/relayers/Cargo.toml b/primitives/relayers/Cargo.toml index 4f893f9f83e..acede813995 100644 --- a/primitives/relayers/Cargo.toml +++ b/primitives/relayers/Cargo.toml @@ -11,6 +11,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" # Bridge Dependencies bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } # Substrate Dependencies @@ -27,6 +28,7 @@ hex-literal = "0.3" default = ["std"] std = [ "bp-messages/std", + "bp-runtime/std", "frame-support/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/relayers/src/lib.rs b/primitives/relayers/src/lib.rs index d00b5f626e4..207908296cb 100644 --- a/primitives/relayers/src/lib.rs +++ b/primitives/relayers/src/lib.rs @@ -20,8 +20,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use bp_messages::LaneId; +use bp_runtime::StorageDoubleMapKeyProvider; +use frame_support::{Blake2_128Concat, Identity}; use sp_runtime::{ - codec::{Decode, Encode}, + codec::{Codec, Decode, Encode, EncodeLike}, traits::AccountIdConversion, }; use sp_std::{fmt::Debug, marker::PhantomData}; @@ -65,6 +67,24 @@ where } } +/// Can be use to access the runtime storage key within the `RelayerRewards` map of the relayers +/// pallet. +pub struct RelayerRewardsKeyProvider(PhantomData<(AccountId, Reward)>); + +impl StorageDoubleMapKeyProvider for RelayerRewardsKeyProvider +where + AccountId: Codec + EncodeLike, + Reward: Codec + EncodeLike, +{ + const MAP_NAME: &'static str = "RelayerRewards"; + + type Hasher1 = Blake2_128Concat; + type Key1 = AccountId; + type Hasher2 = Identity; + type Key2 = LaneId; + type Value = Reward; +} + #[cfg(test)] mod tests { use super::*; diff --git a/primitives/runtime/src/extensions.rs b/primitives/runtime/src/extensions.rs index 287f484db4a..eefe10f7057 100644 --- a/primitives/runtime/src/extensions.rs +++ b/primitives/runtime/src/extensions.rs @@ -96,8 +96,8 @@ pub struct GenericSignedExtension { } impl GenericSignedExtension { - pub fn new(payload: S::Payload, additional_signed: S::AdditionalSigned) -> Self { - Self { payload, additional_signed: Some(additional_signed) } + pub fn new(payload: S::Payload, additional_signed: Option) -> Self { + Self { payload, additional_signed } } } diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs index ea6d6ad9f51..193632c28b4 100644 --- a/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs @@ -61,8 +61,8 @@ use crate::{ use bp_messages::LaneId; use bp_runtime::BalanceOf; use relay_substrate_client::{ - AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithTransactions, Client, - Parachain, + AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithMessages, + ChainWithTransactions, Client, Parachain, }; use relay_utils::metrics::MetricsParams; use sp_core::Pair; @@ -259,9 +259,9 @@ where type Base: Full2WayBridgeBase; /// The left relay chain. - type Left: ChainWithTransactions + ChainWithBalances + CliChain; + type Left: ChainWithTransactions + ChainWithBalances + ChainWithMessages + CliChain; /// The right relay chain. - type Right: ChainWithTransactions + ChainWithBalances + CliChain; + type Right: ChainWithTransactions + ChainWithBalances + ChainWithMessages + CliChain; /// Left to Right bridge. type L2R: MessagesCliBridge; @@ -317,28 +317,36 @@ where self.mut_base().start_on_demand_headers_relayers().await?; // add balance-related metrics + let lanes = self + .base() + .common() + .shared + .lane + .iter() + .cloned() + .map(Into::into) + .collect::>(); { let common = self.mut_base().mut_common(); - substrate_relay_helper::messages_metrics::add_relay_balances_metrics( + substrate_relay_helper::messages_metrics::add_relay_balances_metrics::<_, Self::Right>( common.left.client.clone(), &mut common.metrics_params, &common.left.accounts, + &lanes, ) .await?; - substrate_relay_helper::messages_metrics::add_relay_balances_metrics( + substrate_relay_helper::messages_metrics::add_relay_balances_metrics::<_, Self::Left>( common.right.client.clone(), &mut common.metrics_params, &common.right.accounts, + &lanes, ) .await?; } - let lanes = self.base().common().shared.lane.clone(); // Need 2x capacity since we consider both directions for each lane let mut message_relays = Vec::with_capacity(lanes.len() * 2); for lane in lanes { - let lane = lane.into(); - let left_to_right_messages = substrate_relay_helper::messages_lane::run::< ::MessagesLane, >(self.left_to_right().messages_relay_params( diff --git a/relays/client-bridge-hub-rococo/src/lib.rs b/relays/client-bridge-hub-rococo/src/lib.rs index 8e6e9712925..b14a9baa61d 100644 --- a/relays/client-bridge-hub-rococo/src/lib.rs +++ b/relays/client-bridge-hub-rococo/src/lib.rs @@ -66,7 +66,7 @@ impl ChainWithTransactions for BridgeHubRococo { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - bp_bridge_hub_rococo::BridgeSignedExtension::from_params( + bp_bridge_hub_rococo::SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, @@ -110,6 +110,7 @@ impl ChainWithTransactions for BridgeHubRococo { impl ChainWithMessages for BridgeHubRococo { const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME; + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = None; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_bridge_hub_rococo::TO_BRIDGE_HUB_ROCOCO_MESSAGE_DETAILS_METHOD; diff --git a/relays/client-bridge-hub-rococo/src/runtime_wrapper.rs b/relays/client-bridge-hub-rococo/src/runtime_wrapper.rs index 1bb32a4089c..7f526a35aa9 100644 --- a/relays/client-bridge-hub-rococo/src/runtime_wrapper.rs +++ b/relays/client-bridge-hub-rococo/src/runtime_wrapper.rs @@ -21,14 +21,14 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; -use bp_bridge_hub_rococo::BridgeSignedExtension; +use bp_bridge_hub_rococo::SignedExtension; pub use bp_header_chain::BridgeGrandpaCallOf; pub use bp_parachains::BridgeParachainCall; pub use bridge_runtime_common::messages::BridgeMessagesCallOf; pub use relay_substrate_client::calls::SystemCall; /// Unchecked BridgeHubRococo extrinsic. -pub type UncheckedExtrinsic = bp_bridge_hub_rococo::UncheckedExtrinsic; +pub type UncheckedExtrinsic = bp_bridge_hub_rococo::UncheckedExtrinsic; // The indirect pallet call used to sync `Wococo` GRANDPA finality to `BHRococo`. pub type BridgeWococoGrandpaCall = BridgeGrandpaCallOf; diff --git a/relays/client-bridge-hub-wococo/src/lib.rs b/relays/client-bridge-hub-wococo/src/lib.rs index 3fd8187fa1f..abc820ed624 100644 --- a/relays/client-bridge-hub-wococo/src/lib.rs +++ b/relays/client-bridge-hub-wococo/src/lib.rs @@ -66,7 +66,7 @@ impl ChainWithTransactions for BridgeHubWococo { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - bp_bridge_hub_wococo::BridgeSignedExtension::from_params( + bp_bridge_hub_wococo::SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, @@ -110,6 +110,7 @@ impl ChainWithTransactions for BridgeHubWococo { impl ChainWithMessages for BridgeHubWococo { const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME; + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = None; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_bridge_hub_wococo::TO_BRIDGE_HUB_WOCOCO_MESSAGE_DETAILS_METHOD; diff --git a/relays/client-bridge-hub-wococo/src/runtime_wrapper.rs b/relays/client-bridge-hub-wococo/src/runtime_wrapper.rs index 2158ad0e659..85f77a6377e 100644 --- a/relays/client-bridge-hub-wococo/src/runtime_wrapper.rs +++ b/relays/client-bridge-hub-wococo/src/runtime_wrapper.rs @@ -19,14 +19,14 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; -use bp_bridge_hub_wococo::BridgeSignedExtension; +use bp_bridge_hub_wococo::SignedExtension; pub use bp_header_chain::BridgeGrandpaCallOf; pub use bp_parachains::BridgeParachainCall; pub use bridge_runtime_common::messages::BridgeMessagesCallOf; pub use relay_substrate_client::calls::SystemCall; /// Unchecked BridgeHubWococo extrinsic. -pub type UncheckedExtrinsic = bp_bridge_hub_wococo::UncheckedExtrinsic; +pub type UncheckedExtrinsic = bp_bridge_hub_wococo::UncheckedExtrinsic; // The indirect pallet call used to sync `Rococo` GRANDPA finality to `BHWococo`. pub type BridgeRococoGrandpaCall = BridgeGrandpaCallOf; diff --git a/relays/client-millau/src/lib.rs b/relays/client-millau/src/lib.rs index fb901a4b2de..34bbea92d57 100644 --- a/relays/client-millau/src/lib.rs +++ b/relays/client-millau/src/lib.rs @@ -45,6 +45,8 @@ impl ChainWithGrandpa for Millau { impl ChainWithMessages for Millau { const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; + // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): change the name + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = Some("BridgeRelayers"); const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD; const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = diff --git a/relays/client-rialto-parachain/src/lib.rs b/relays/client-rialto-parachain/src/lib.rs index ebaac73e036..d6efd6581b2 100644 --- a/relays/client-rialto-parachain/src/lib.rs +++ b/relays/client-rialto-parachain/src/lib.rs @@ -19,7 +19,7 @@ pub mod runtime_wrapper; use bp_messages::MessageNonce; -use bp_polkadot_core::{DefaultSignedExtension, PolkadotSignedExtension}; +use bp_polkadot_core::PolkadotSignedExtension; use codec::Encode; use relay_substrate_client::{ Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions, Error as SubstrateError, @@ -63,6 +63,8 @@ impl ChainWithBalances for RialtoParachain { impl ChainWithMessages for RialtoParachain { const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = bp_rialto_parachain::WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME; + // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): change the name + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = Some("BridgeRelayers"); const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_rialto_parachain::TO_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD; const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = @@ -77,7 +79,7 @@ impl ChainWithMessages for RialtoParachain { impl ChainWithTransactions for RialtoParachain { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = - bp_polkadot_core::UncheckedExtrinsic; + bp_polkadot_core::UncheckedExtrinsic; fn sign_transaction( param: SignParam, @@ -85,7 +87,7 @@ impl ChainWithTransactions for RialtoParachain { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - bp_polkadot_core::DefaultSignedExtension::from_params( + bp_rialto_parachain::SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/relays/client-rialto/src/lib.rs b/relays/client-rialto/src/lib.rs index 4c3a9d1e18e..8ad31de4d58 100644 --- a/relays/client-rialto/src/lib.rs +++ b/relays/client-rialto/src/lib.rs @@ -63,6 +63,8 @@ impl ChainWithGrandpa for Rialto { impl ChainWithMessages for Rialto { const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME; + // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): change the name + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = Some("BridgeRelayers"); const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD; const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = diff --git a/relays/client-substrate/src/chain.rs b/relays/client-substrate/src/chain.rs index db08fc1f98c..4ec5edfc41b 100644 --- a/relays/client-substrate/src/chain.rs +++ b/relays/client-substrate/src/chain.rs @@ -101,6 +101,16 @@ pub trait ChainWithMessages: Chain { /// the same name. const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str; + // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): check all the names + // after the issue is fixed - all names must be changed + + /// Name of the bridge relayers pallet (used in `construct_runtime` macro call) that is deployed + /// at some other chain to bridge with this `ChainWithMessages`. + /// + /// We assume that all chains that are bridging with this `ChainWithMessages` are using + /// the same name. + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str>; + /// Name of the `ToOutboundLaneApi::message_details` runtime API method. /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str; diff --git a/relays/finality/README.md b/relays/finality/README.md new file mode 100644 index 00000000000..edfd00192bc --- /dev/null +++ b/relays/finality/README.md @@ -0,0 +1,58 @@ +# GRANDPA Finality Relay + +The finality relay is able to work with different finality engines. In the modern Substrate world they are GRANDPA +and BEEFY. Let's talk about GRANDPA here, because BEEFY relay and bridge BEEFY pallet are in development. + +In general, the relay works as follows: it connects to the source and target chain. The source chain must have the +[GRANDPA gadget](https://github.com/paritytech/finality-grandpa) running (so it can't be a parachain). The target +chain must have the [bridge GRANDPA pallet](../../modules/grandpa/) deployed at its runtime. The relay subscribes +to the GRANDPA finality notifications at the source chain and when the new justification is received, it is submitted +to the pallet at the target chain. + +Apart from that, the relay is watching for every source header that is missing at target. If it finds the missing +mandatory header (header that is changing the current GRANDPA validators set), it submits the justification for +this header. The case when the source node can't return the mandatory justification is considered a fatal error, +because the pallet can't proceed without it. + +More: [GRANDPA Finality Relay Sequence Diagram](../../docs/grandpa-finality-relay.html). + +## How to Use the Finality Relay + +The most important trait is the [`FinalitySyncPipeline`](./src/lib.rs), which defines the basic primitives of the +source chain (like block hash and number) and the type of finality proof (GRANDPA jusitfication or MMR proof). Once +that is defined, there are two other traits - [`SourceClient`](./src/finality_loop.rs) and +[`TarggetClient`](./src/finality_loop.rs). + +The `SourceClient` represents the Substrate node client that connects to the source chain. The client need to +be able to return the best finalized header number, finalized header and its finality proof and the stream of +finality proofs. + +The `TargetClient` implementation must be able to craft finality delivery transaction and submit it to the target +node. The transaction is then tracked by the relay until it is mined and finalized. + +The main entrypoint for the crate is the [`run` function](./src/finality_loop.rs), which takes source and target +clients and [`FinalitySyncParams`](./src/finality_loop.rs) parameters. The most imporant parameter is the +`only_mandatory_headers` - it it is set to `true`, the relay will only submit mandatory headers. Since transactions +with mandatory headers are fee-free, the cost of running such relay is zero (in terms of fees). + +## Finality Relay Metrics + +Finality relay provides several metrics. Metrics names depend on names of source and target chains. The list below +shows metrics names for Rialto (source chain) to Millau (target chain) finality relay. For other chains, simply +change chain names. So the metrics are: + +- `Rialto_to_Millau_Sync_best_source_block_number` - returns best finalized source chain (Rialto) block number, known + to the relay. If relay is running in [on-demand mode](../bin-substrate/src/cli/relay_headers_and_messages/), the + number may not match (it may be far behind) the actual best finalized number; + +- `Rialto_to_Millau_Sync_best_source_at_target_block_number` - returns best finalized source chain (Rialto) block + number that is known to the bridge GRANDPA pallet at the target chain. + +- `Rialto_to_Millau_Sync_is_source_and_source_at_target_using_different_forks` - if this metrics is set to `1`, then + the best source chain header, known to the target chain doesn't match the same-number-header at the source chain. + It means that the GRANDPA validators set has crafted the duplicate justification and it has been submitted to the + target chain. Normally (if majority of validators are honest and if you're running finality relay without large + breaks) this shall not happen and the metric will have `0` value. + +If relay operates properly, you should see that the `Rialto_to_Millau_Sync_best_source_at_target_block_number` +tries to reach the `Rialto_to_Millau_Sync_best_source_block_number`. And the latter one always increases. \ No newline at end of file diff --git a/relays/lib-substrate-relay/Cargo.toml b/relays/lib-substrate-relay/Cargo.toml index bdf49d42eab..e044be0957c 100644 --- a/relays/lib-substrate-relay/Cargo.toml +++ b/relays/lib-substrate-relay/Cargo.toml @@ -12,6 +12,7 @@ async-std = "1.9.0" async-trait = "0.1" codec = { package = "parity-scale-codec", version = "3.1.5" } futures = "0.3.12" +hex = "0.4" num-traits = "0.2" log = "0.4.17" @@ -20,6 +21,7 @@ log = "0.4.17" bp-header-chain = { path = "../../primitives/header-chain" } bp-parachains = { path = "../../primitives/parachains" } bp-polkadot-core = { path = "../../primitives/polkadot-core" } +bp-relayers = { path = "../../primitives/relayers" } bridge-runtime-common = { path = "../../bin/runtime-common" } finality-grandpa = { version = "0.16.0" } diff --git a/relays/lib-substrate-relay/src/messages_metrics.rs b/relays/lib-substrate-relay/src/messages_metrics.rs index 37a6d67baae..943f3b7c369 100644 --- a/relays/lib-substrate-relay/src/messages_metrics.rs +++ b/relays/lib-substrate-relay/src/messages_metrics.rs @@ -18,12 +18,15 @@ use crate::TaggedAccount; +use bp_messages::LaneId; +use bp_runtime::StorageDoubleMapKeyProvider; use codec::Decode; use frame_system::AccountInfo; use pallet_balances::AccountData; use relay_substrate_client::{ metrics::{FloatStorageValue, FloatStorageValueMetric}, - AccountIdOf, BalanceOf, Chain, ChainWithBalances, Client, Error as SubstrateError, IndexOf, + AccountIdOf, BalanceOf, Chain, ChainWithBalances, ChainWithMessages, Client, + Error as SubstrateError, IndexOf, }; use relay_utils::metrics::{MetricsParams, StandaloneMetric}; use sp_core::storage::StorageData; @@ -31,10 +34,11 @@ use sp_runtime::{FixedPointNumber, FixedU128}; use std::{convert::TryFrom, fmt::Debug, marker::PhantomData}; /// Add relay accounts balance metrics. -pub async fn add_relay_balances_metrics( +pub async fn add_relay_balances_metrics( client: Client, metrics: &mut MetricsParams, relay_accounts: &Vec>>, + lanes: &[LaneId], ) -> anyhow::Result<()> where BalanceOf: Into + std::fmt::Debug, @@ -68,13 +72,30 @@ where for account in relay_accounts { let relay_account_balance_metric = FloatStorageValueMetric::new( - FreeAccountBalance:: { token_decimals, _phantom: Default::default() }, + AccountBalanceFromAccountInfo:: { token_decimals, _phantom: Default::default() }, client.clone(), C::account_info_storage_key(account.id()), format!("at_{}_relay_{}_balance", C::NAME, account.tag()), format!("Balance of the {} relay account at the {}", account.tag(), C::NAME), )?; relay_account_balance_metric.register_and_spawn(&metrics.registry)?; + + if let Some(relayers_pallet_name) = BC::WITH_CHAIN_RELAYERS_PALLET_NAME { + for lane in lanes { + let relay_account_reward_metric = FloatStorageValueMetric::new( + AccountBalance:: { token_decimals, _phantom: Default::default() }, + client.clone(), + bp_relayers::RelayerRewardsKeyProvider::, BalanceOf>::final_key( + relayers_pallet_name, + account.id(), + lane, + ), + format!("at_{}_relay_{}_reward_for_lane_{}_with_{}", C::NAME, account.tag(), hex::encode(lane.as_ref()), BC::NAME), + format!("Reward of the {} relay account for serving lane {:?} with {} at the {}", account.tag(), lane, BC::NAME, C::NAME), + )?; + relay_account_reward_metric.register_and_spawn(&metrics.registry)?; + } + } } Ok(()) @@ -82,12 +103,12 @@ where /// Adapter for `FloatStorageValueMetric` to decode account free balance. #[derive(Clone, Debug)] -struct FreeAccountBalance { +struct AccountBalanceFromAccountInfo { token_decimals: u32, _phantom: PhantomData, } -impl FloatStorageValue for FreeAccountBalance +impl FloatStorageValue for AccountBalanceFromAccountInfo where C: Chain, BalanceOf: Into, @@ -110,6 +131,34 @@ where } } +/// Adapter for `FloatStorageValueMetric` to decode account free balance. +#[derive(Clone, Debug)] +struct AccountBalance { + token_decimals: u32, + _phantom: PhantomData, +} + +impl FloatStorageValue for AccountBalance +where + C: Chain, + BalanceOf: Into, +{ + type Value = FixedU128; + + fn decode( + &self, + maybe_raw_value: Option, + ) -> Result, SubstrateError> { + maybe_raw_value + .map(|raw_value| { + BalanceOf::::decode(&mut &raw_value.0[..]) + .map_err(SubstrateError::ResponseParseFailed) + .map(|balance| convert_to_token_balance(balance.into(), self.token_decimals)) + }) + .transpose() + } +} + /// Convert from raw `u128` balance (nominated in smallest chain token units) to the float regular /// tokens value. fn convert_to_token_balance(balance: u128, token_decimals: u32) -> FixedU128 { diff --git a/relays/parachains/README.md b/relays/parachains/README.md new file mode 100644 index 00000000000..6cb68f2209f --- /dev/null +++ b/relays/parachains/README.md @@ -0,0 +1,49 @@ +# Parachains Finality Relay + +The parachains finality relay works with two chains - source relay chain and target chain (which may be standalone +chain, relay chain or a parachain). The source chain must have the +[`paras` pallet](https://github.com/paritytech/polkadot/tree/master/runtime/parachains/src/paras) deployed at its +runtime. The target chain must have the [bridge parachains pallet](../../modules/parachains/) deployed at its runtime. + +The relay is configured to submit heads of one or several parachains. It pokes source chain periodically and compares +parachain heads that are known to the source relay chain to heads at the target chain. If there are new heads, +the relay submits them to the target chain. + +More: [Parachains Finality Relay Sequence Diagram](../../docs/parachains-finality-relay.html). + +## How to Use the Parachains Finality Relay + +There are only two traits that need to be implemented. The [`SourceChain`](./src/parachains_loop.rs) implementation +is supposed to connect to the source chain node. It must be able to read parachain heads from the `Heads` map of +the [`paras` pallet](https://github.com/paritytech/polkadot/tree/master/runtime/parachains/src/paras) pallet. +It also must create storage proofs of `Heads` map entries, when required. + +The [`TargetChain`](./src/parachains_loop.rs) implementation connects to the target chain node. It must be able +to return the best known head of given parachain. When required, it must be able to craft and submit parachains +finality delivery transaction to the target node. + +The main entrypoint for the crate is the [`run` function](./src/parachains_loop.rs), which takes source and target +clients and [`ParachainSyncParams`](./src/parachains_loop.rs) parameters. The most imporant parameter is the +`parachains` - it it the set of parachains, which relay tracks and updates. The other important parameter that +may affect the relay operational costs is the `strategy`. If it is set to `Any`, then the finality delivery +transaction is submitted if at least one of tracked parachain heads is updated. The other option is `All`. Then +the relay waits until all tracked parachain heads are updated and submits them all in a single finality delivery +transaction. + +## Parachain Finality Relay Metrics + +Every parachain in Polkadot is identified by the 32-bit number. All metrics, exposed by the parachains finality +relay have the `parachain` label, which is set to the parachain id. And the metrics are prefixed with the prefix, +that depends on the name of the source relay and target chains. The list below shows metrics names for +Rialto (source relay chain) to Millau (target chain) parachains finality relay. For other chains, simply +change chain names. So the metrics are: + +- `Rialto_to_Millau_Parachains_best_parachain_block_number_at_source` - returns best known parachain block + number, registered in the `paras` pallet at the source relay chain (Rialto in our example); + +- `Rialto_to_Millau_Parachains_best_parachain_block_number_at_target` - returns best known parachain block + number, registered in the bridge parachains pallet at the target chain (Millau in our example). + +If relay operates properly, you should see that the `Rialto_to_Millau_Parachains_best_parachain_block_number_at_target` +tries to reach the `Rialto_to_Millau_Parachains_best_parachain_block_number_at_source`. And the latter one +always increases.