Skip to content

Commit

Permalink
Convert ECDSA Public Keys to EVM Addresses when building voters' merk…
Browse files Browse the repository at this point in the history
…le tree (#721)

* cargo fmt

* flake.lock: Update

Flake lock file updates:

• Updated input 'flake-utils':
    'github:numtide/flake-utils/cfacdce06f30d2b68473a46042957675eebb3401' (2023-04-11)
  → 'github:numtide/flake-utils/ff7b65b44d01cf9ba6a71320833626af21126384' (2023-09-12)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/8670e496ffd093b60e74e7fa53526aa5920d09eb' (2023-05-01)
  → 'github:NixOS/nixpkgs/2646b294a146df2781b1ca49092450e8a32814e1' (2023-10-08)
• Updated input 'rust-overlay':
    'github:oxalica/rust-overlay/07f421299826591e2b28e03bbbe19a5292395afe' (2023-05-02)
  → 'github:oxalica/rust-overlay/c0df7f2a856b5ff27a3ce314f6d7aacf5fda546f' (2023-10-09)

* Convert ECDSA Public Keys to EVM Addresses when building the merkle tree

* pump runtime version

* Update types

* Pump pallet versions
  • Loading branch information
shekohex authored Oct 10, 2023
1 parent ea2659e commit af579a3
Show file tree
Hide file tree
Showing 21 changed files with 480 additions and 426 deletions.
7 changes: 4 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pallets/dkg-metadata/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "pallet-dkg-metadata"
description = "FRAME pallet for DKG metadata"
version = "0.1.0"
version = "0.2.0"
authors = { workspace = true }
license = { workspace = true }
publish = { workspace = true }
Expand Down Expand Up @@ -37,6 +37,7 @@ sp-core = { workspace = true }
sp-io = { workspace = true }
sp-staking = { workspace = true }
sp-keystore = { workspace = true }
k256 = { version = "0.11.5", default-features = false, features = ["arithmetic", "ecdsa"] }

[features]
default = ["std"]
Expand Down
27 changes: 19 additions & 8 deletions pallets/dkg-metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,12 @@ use weights::WeightInfo;
// Reputation assigned to genesis authorities
pub const INITIAL_REPUTATION: u32 = 1_000_000_000;

// Our goal is to trigger the ShouldExecuteNewKeygen to true if we have passed exactly X blocks from the last session rotation
// and still have not seen a new key, this value cannot be too small either because we need to accomodate delays between `keygen
// process starting + completion + posted onchain`. If the delay is smaller than the above then we might inadvertently rotate
// Our goal is to trigger the ShouldExecuteNewKeygen to true if we have passed exactly X blocks from
// the last session rotation and still have not seen a new key, this value cannot be too small
// either because we need to accomodate delays between `keygen process starting + completion +
// posted onchain`. If the delay is smaller than the above then we might inadvertently rotate
// sessions.
pub const BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER : u32 = 20;
pub const BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER: u32 = 20;

// Reputation increase awarded to authorities on submission of next public key
pub const REPUTATION_INCREMENT: u32 = INITIAL_REPUTATION / 1000;
Expand Down Expand Up @@ -210,6 +211,13 @@ pub mod pallet {
+ Into<ecdsa::Public>
+ From<ecdsa::Public>
+ MaxEncodedLen;
/// Convert DKG AuthorityId to a form that would end up in the Merkle Tree.
///
/// For instance for ECDSA (secp256k1) we want to store uncompressed public keys (65 bytes)
/// and later to Ethereum Addresses (160 bits) to simplify using them on Ethereum chain,
/// but the rest of the Substrate codebase is storing them compressed (33 bytes) for
/// efficiency reasons.
type DKGAuthorityToMerkleLeaf: Convert<Self::DKGId, Vec<u8>>;
/// Jail lengths for misbehaviours
type KeygenJailSentence: Get<BlockNumberFor<Self>>;
type SigningJailSentence: Get<BlockNumberFor<Self>>;
Expand Down Expand Up @@ -409,12 +417,15 @@ pub mod pallet {

// Our goal is to trigger the ShouldExecuteNewKeygen if either of the two conditions are
// true : 1. A SessionPeriod of blocks have passed from the LastSessionRotationBlock
// 2. If 1 is true and we have not yet seen NextKey on chain for the last BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER blocks
// check if we have passed exactly `Period` blocks from the last session rotation
// 2. If 1 is true and we have not yet seen NextKey on chain for the last
// BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER blocks check if we have passed exactly
// `Period` blocks from the last session rotation
let blocks_passed_since_last_session_rotation =
n - LastSessionRotationBlock::<T>::get();
if blocks_passed_since_last_session_rotation >= T::SessionPeriod::get() &&
blocks_passed_since_last_session_rotation % BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER.into() == 0u32.into()
blocks_passed_since_last_session_rotation %
BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER.into() ==
0u32.into()
{
// lets set the ShouldStartDKG to true
// we dont set force_keygen to true, that is reserved for emergency rotate
Expand Down Expand Up @@ -1633,7 +1644,7 @@ impl<T: Config> Pallet<T> {
// Hash the external accounts into 32 byte chunks to form the base layer of the merkle tree
let mut base_layer: Vec<[u8; 32]> = voters
.iter()
.map(|account| account.to_raw_vec())
.map(|account| T::DKGAuthorityToMerkleLeaf::convert(account.clone()))
.map(|account| keccak_256(&account))
.collect();
// Pad base_layer to have length 2^height
Expand Down
25 changes: 23 additions & 2 deletions pallets/dkg-metadata/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use sp_runtime::{
impl_opaque_keys,
testing::TestXt,
traits::{
BlakeTwo256, ConvertInto, Extrinsic as ExtrinsicT, IdentifyAccount, IdentityLookup,
OpaqueKeys, Verify,
BlakeTwo256, Convert, ConvertInto, Extrinsic as ExtrinsicT, IdentifyAccount,
IdentityLookup, OpaqueKeys, Verify,
},
BuildStorage, Percent, Permill,
};
Expand Down Expand Up @@ -141,6 +141,7 @@ parameter_types! {

impl pallet_dkg_metadata::Config for Test {
type DKGId = DKGId;
type DKGAuthorityToMerkleLeaf = DKGEcdsaToEthereumAddress;
type RuntimeEvent = RuntimeEvent;
type OnAuthoritySetChangeHandler = ();
type OnDKGPublicKeyChangeHandler = ();
Expand Down Expand Up @@ -254,3 +255,23 @@ pub fn new_test_ext_raw_authorities(authorities: Vec<(AccountId, DKGId)>) -> Tes
ext.register_extension(KeystoreExt(Arc::new(MemoryKeystore::new()) as KeystorePtr));
ext
}

/// Convert DKG secp256k1 public keys into Ethereum addresses
pub struct DKGEcdsaToEthereumAddress;
impl Convert<dkg_runtime_primitives::crypto::AuthorityId, Vec<u8>> for DKGEcdsaToEthereumAddress {
fn convert(a: dkg_runtime_primitives::crypto::AuthorityId) -> Vec<u8> {
use k256::{ecdsa::VerifyingKey, elliptic_curve::sec1::ToEncodedPoint};
let _x = VerifyingKey::from_sec1_bytes(sp_core::crypto::ByteArray::as_slice(&a));
VerifyingKey::from_sec1_bytes(sp_core::crypto::ByteArray::as_slice(&a))
.map(|pub_key| {
// uncompress the key
let uncompressed = pub_key.to_encoded_point(false);
// convert to ETH address
sp_io::hashing::keccak_256(&uncompressed.as_bytes()[1..])[12..].to_vec()
})
.map_err(|_| {
log::error!(target: "runtime::dkg_proposals", "Invalid DKG PublicKey format!");
})
.unwrap_or_default()
}
}
1 change: 1 addition & 0 deletions pallets/dkg-proposal-handler/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ parameter_types! {
impl pallet_dkg_metadata::Config for Test {
type DKGId = DKGId;
type RuntimeEvent = RuntimeEvent;
type DKGAuthorityToMerkleLeaf = DKGEcdsaToEthereumAddress;
type OnAuthoritySetChangeHandler = ();
type OnDKGPublicKeyChangeHandler = ();
type OffChainAuthId = dkg_runtime_primitives::offchain::crypto::OffchainAuthId;
Expand Down
1 change: 1 addition & 0 deletions pallets/dkg-proposals/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ parameter_types! {

impl pallet_dkg_metadata::Config for Test {
type DKGId = DKGId;
type DKGAuthorityToMerkleLeaf = DKGEcdsaToEthereumAddress;
type RuntimeEvent = RuntimeEvent;
type OnAuthoritySetChangeHandler = DKGProposals;
type OnDKGPublicKeyChangeHandler = ();
Expand Down
2 changes: 1 addition & 1 deletion standalone/node/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dkg-standalone-node"
version = "3.0.0"
version = "3.1.0"
build = "build.rs"
description = { workspace = true }
authors = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion standalone/runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dkg-standalone-runtime"
version = "3.0.0"
version = "3.1.0"
description = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
Expand Down
3 changes: 2 additions & 1 deletion standalone/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("dkg-standalone-node"),
impl_name: create_runtime_str!("dkg-standalone-node"),
authoring_version: 1,
spec_version: 19,
spec_version: 20,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down Expand Up @@ -607,6 +607,7 @@ parameter_types! {

impl pallet_dkg_metadata::Config for Runtime {
type DKGId = DKGId;
type DKGAuthorityToMerkleLeaf = pallet_dkg_proposals::DKGEcdsaToEthereumAddress;
type RuntimeEvent = RuntimeEvent;
type OnAuthoritySetChangeHandler = DKGProposals;
type OnDKGPublicKeyChangeHandler = ();
Expand Down
130 changes: 65 additions & 65 deletions types/package.json
Original file line number Diff line number Diff line change
@@ -1,67 +1,67 @@
{
"name": "@webb-tools/dkg-substrate-types",
"version": "0.0.6",
"description": "Polkadot.js type definitions required for interacting with Webb's DKG protocol",
"main": "./build/index.js",
"author": "Webb Developers <drew@webb.tools>",
"license": "Apache-2.0",
"type": "commonjs",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"repository": "https://github.com/webb-tools/dkg-substrate.git",
"bugs": {
"url": "https://github.com/webb-tools/dkg-substrate/issues"
},
"homepage": "https://github.com/webb-tools/dkg-substrate",
"dependencies": {
"@babel/cli": "^7.20.7",
"@babel/core": "^7.20.12",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
"@babel/plugin-proposal-numeric-separator": "^7.18.6",
"@babel/plugin-proposal-optional-chaining": "^7.20.7",
"@babel/plugin-syntax-bigint": "^7.8.3",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-import-assertions": "^7.20.0",
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/plugin-syntax-top-level-await": "^7.14.5",
"@babel/plugin-transform-regenerator": "^7.20.5",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@babel/register": "^7.18.9",
"@babel/runtime": "^7.20.13",
"babel-jest": "^29.4.1",
"babel-plugin-module-extension-resolver": "^1.0.0",
"babel-plugin-module-resolver": "^5.0.0",
"babel-plugin-styled-components": "^2.0.7",
"@open-web3/orml-types": "^1.1.3",
"@polkadot/api-derive": "10.4.1",
"@polkadot/dev": "^0.72.42",
"@polkadot/typegen": "10.4.1",
"@polkadot/types": "10.4.1",
"fs-extra": "^11.1.1",
"glob2base": "^0.0.12",
"minimatch": "^7.4.2",
"mkdirp": "^2.1.5"
},
"devDependencies": {
"@types/websocket": "^1.0.0",
"rimraf": "3.0.2",
"ts-node": "10.9.1",
"tsconfig-paths": "^4.2.0",
"typescript": "5.0.4",
"websocket": "^1.0.31"
},
"scripts": {
"build": "node ./scripts/build.js",
"build:interfaces": "yarn build:interfaces:defs && yarn build:interfaces:chain && rm ./src/interfaces/index.ts && rm ./src/interfaces/types.ts",
"build:interfaces:defs": "npx ts-node node_modules/.bin/polkadot-types-from-defs --input ./src/interfaces --package @webb-tools/dkg-substrate-types --endpoint ./src/metadata/metadata.json",
"build:interfaces:chain": "npx ts-node node_modules/.bin/polkadot-types-from-chain --endpoint ./src/metadata/metadata.json --output ./src/interfaces",
"clean": "rm -rf build && rm -rf ts-types",
"publish-types": "node ./scripts/publish-types.js",
"update:metadata": "npx ts-node ./scripts/updateMetadata.ts"
}
"name": "@webb-tools/dkg-substrate-types",
"version": "0.0.7",
"description": "Polkadot.js type definitions required for interacting with Webb's DKG protocol",
"main": "./build/index.js",
"author": "Webb Developers <drew@webb.tools>",
"license": "Apache-2.0",
"type": "commonjs",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"repository": "https://github.com/webb-tools/dkg-substrate.git",
"bugs": {
"url": "https://github.com/webb-tools/dkg-substrate/issues"
},
"homepage": "https://github.com/webb-tools/dkg-substrate",
"dependencies": {
"@babel/cli": "^7.20.7",
"@babel/core": "^7.20.12",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
"@babel/plugin-proposal-numeric-separator": "^7.18.6",
"@babel/plugin-proposal-optional-chaining": "^7.20.7",
"@babel/plugin-syntax-bigint": "^7.8.3",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-import-assertions": "^7.20.0",
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/plugin-syntax-top-level-await": "^7.14.5",
"@babel/plugin-transform-regenerator": "^7.20.5",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@babel/register": "^7.18.9",
"@babel/runtime": "^7.20.13",
"babel-jest": "^29.4.1",
"babel-plugin-module-extension-resolver": "^1.0.0",
"babel-plugin-module-resolver": "^5.0.0",
"babel-plugin-styled-components": "^2.0.7",
"@open-web3/orml-types": "^1.1.3",
"@polkadot/api-derive": "10.4.1",
"@polkadot/dev": "^0.72.42",
"@polkadot/typegen": "10.4.1",
"@polkadot/types": "10.4.1",
"fs-extra": "^11.1.1",
"glob2base": "^0.0.12",
"minimatch": "^7.4.2",
"mkdirp": "^2.1.5"
},
"devDependencies": {
"@types/websocket": "^1.0.0",
"rimraf": "3.0.2",
"ts-node": "10.9.1",
"tsconfig-paths": "^4.2.0",
"typescript": "5.0.4",
"websocket": "^1.0.31"
},
"scripts": {
"build": "node ./scripts/build.js",
"build:interfaces": "yarn build:interfaces:defs && yarn build:interfaces:chain && rm ./src/interfaces/index.ts && rm ./src/interfaces/types.ts",
"build:interfaces:defs": "npx ts-node node_modules/.bin/polkadot-types-from-defs --input ./src/interfaces --package @webb-tools/dkg-substrate-types --endpoint ./src/metadata/metadata.json",
"build:interfaces:chain": "npx ts-node node_modules/.bin/polkadot-types-from-chain --endpoint ./src/metadata/metadata.json --output ./src/interfaces",
"clean": "rm -rf build && rm -rf ts-types",
"publish-types": "node ./scripts/publish-types.js",
"update:metadata": "npx ts-node ./scripts/updateMetadata.ts"
}
}
1 change: 1 addition & 0 deletions types/src/interfaces/augment-api-consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { ApiTypes, AugmentedConst } from '@polkadot/api-base/types';
import type { Vec, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
import type { Codec } from '@polkadot/types-codec/types';
import type { Perbill } from '@polkadot/types/interfaces/runtime';
import { WebbProposalsHeaderTypedChainId, SpWeightsWeightV2Weight, FrameSupportPalletId, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, SpWeightsRuntimeDbWeight, SpVersionRuntimeVersion } from '@polkadot/types/lookup';

export type __AugmentedConst<ApiType extends ApiTypes> = AugmentedConst<ApiType>;

Expand Down
Loading

0 comments on commit af579a3

Please sign in to comment.