mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Initial multisig tracking contract in ink
This commit is contained in:
240
Cargo.lock
generated
240
Cargo.lock
generated
@@ -106,6 +106,12 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "array-init"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfb6d71005dc22a708c7496eee5c8dc0300ee47355de6256c3b35b12b5fef596"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
@@ -3137,6 +3143,184 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_allocator"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed249de74298ed051ebcf6d3082b8d3dbd19cbc448d9ed3235d8a7b92713049"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_engine"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acb9d32ec27d71fefb3f2b6a26bae82a2c6509d7ad61e8a5107b6291a1b03ecb"
|
||||||
|
dependencies = [
|
||||||
|
"blake2",
|
||||||
|
"derive_more",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"secp256k1 0.22.1",
|
||||||
|
"sha2 0.10.2",
|
||||||
|
"sha3 0.10.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_env"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1549f5966167387c89fb3dfcdc59973bfb396cc3a7110d7a31ad5fdea56db0cf"
|
||||||
|
dependencies = [
|
||||||
|
"arrayref",
|
||||||
|
"blake2",
|
||||||
|
"cfg-if",
|
||||||
|
"derive_more",
|
||||||
|
"ink_allocator",
|
||||||
|
"ink_engine",
|
||||||
|
"ink_metadata",
|
||||||
|
"ink_prelude",
|
||||||
|
"ink_primitives",
|
||||||
|
"num-traits",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"paste",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"rlibc",
|
||||||
|
"scale-info",
|
||||||
|
"secp256k1 0.22.1",
|
||||||
|
"sha2 0.10.2",
|
||||||
|
"sha3 0.10.1",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_lang"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e5282f2722ac6dca469e7f223a7b38b2a6d20fbca6b974497e630d5dc8934e9"
|
||||||
|
dependencies = [
|
||||||
|
"derive_more",
|
||||||
|
"ink_env",
|
||||||
|
"ink_lang_macro",
|
||||||
|
"ink_prelude",
|
||||||
|
"ink_primitives",
|
||||||
|
"ink_storage",
|
||||||
|
"parity-scale-codec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_lang_codegen"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb3a5de33b59450adc3f61c5eb05b768067c7ab8af9d00f33e284310598168dc"
|
||||||
|
dependencies = [
|
||||||
|
"blake2",
|
||||||
|
"derive_more",
|
||||||
|
"either",
|
||||||
|
"heck 0.4.0",
|
||||||
|
"impl-serde",
|
||||||
|
"ink_lang_ir",
|
||||||
|
"itertools",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_lang_ir"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9d4d614462280fa06e15b9ca5725d7c8440dde93c8dae1c6f15422f7756cacb"
|
||||||
|
dependencies = [
|
||||||
|
"blake2",
|
||||||
|
"either",
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_lang_macro"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72f85f64141957c5db7cbabbb97a9c16c489e5e9d363e9f147d132a43c71cd29"
|
||||||
|
dependencies = [
|
||||||
|
"ink_lang_codegen",
|
||||||
|
"ink_lang_ir",
|
||||||
|
"ink_primitives",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"proc-macro2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_metadata"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dca6c159a2774f07437c6fd9ea710eb73a6b5e9a031a932bddf08742bf2c081a"
|
||||||
|
dependencies = [
|
||||||
|
"derive_more",
|
||||||
|
"impl-serde",
|
||||||
|
"ink_prelude",
|
||||||
|
"ink_primitives",
|
||||||
|
"scale-info",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_prelude"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1f7f4dec15e573496c9d2af353e78bde84add391251608f25b5adcf175dc777"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_primitives"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3296dd1c4f4fe12ede7c92d60e6fcb94d46a959ec19c701e4ac588b09e0b4a6"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"ink_prelude",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"scale-info",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_storage"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ff9b503995a7b41fe201a7a2643ce22f5a11e0b67db7b685424b6d5fe0ecf0b"
|
||||||
|
dependencies = [
|
||||||
|
"array-init",
|
||||||
|
"cfg-if",
|
||||||
|
"derive_more",
|
||||||
|
"ink_env",
|
||||||
|
"ink_metadata",
|
||||||
|
"ink_prelude",
|
||||||
|
"ink_primitives",
|
||||||
|
"ink_storage_derive",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"scale-info",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ink_storage_derive"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "afb68e24e93e8327dda1924868d7ee4dbe01e1ed2b392f28583caa96809b585c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"synstructure",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@@ -4529,6 +4713,19 @@ version = "0.8.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multisig-serai"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ink_env",
|
||||||
|
"ink_lang",
|
||||||
|
"ink_metadata",
|
||||||
|
"ink_primitives",
|
||||||
|
"ink_storage",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"scale-info",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multistream-select"
|
name = "multistream-select"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@@ -6092,6 +6289,12 @@ dependencies = [
|
|||||||
"digest 0.10.3",
|
"digest 0.10.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rlibc"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rlp"
|
name = "rlp"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -7192,7 +7395,16 @@ version = "0.21.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c42e6f1735c5f00f51e43e28d6634141f2bcad10931b2609ddd74a86d751260"
|
checksum = "9c42e6f1735c5f00f51e43e28d6634141f2bcad10931b2609ddd74a86d751260"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"secp256k1-sys",
|
"secp256k1-sys 0.4.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "secp256k1"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26947345339603ae8395f68e2f3d85a6b0a8ddfe6315818e80b8504415099db0"
|
||||||
|
dependencies = [
|
||||||
|
"secp256k1-sys 0.5.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7204,6 +7416,15 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "secp256k1-sys"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "152e20a0fd0519390fc43ab404663af8a0b794273d2a91d60ad4a39f13ffe110"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "secrecy"
|
name = "secrecy"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -7842,7 +8063,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
"schnorrkel",
|
"schnorrkel",
|
||||||
"secp256k1",
|
"secp256k1 0.21.3",
|
||||||
"secrecy",
|
"secrecy",
|
||||||
"serde",
|
"serde",
|
||||||
"sp-core-hashing",
|
"sp-core-hashing",
|
||||||
@@ -7957,7 +8178,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
"secp256k1",
|
"secp256k1 0.21.3",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-externalities",
|
"sp-externalities",
|
||||||
"sp-keystore",
|
"sp-keystore",
|
||||||
@@ -8761,6 +8982,19 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "token-serai"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ink_env",
|
||||||
|
"ink_lang",
|
||||||
|
"ink_metadata",
|
||||||
|
"ink_primitives",
|
||||||
|
"ink_storage",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"scale-info",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.20.0"
|
version = "1.20.0"
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ members = [
|
|||||||
|
|
||||||
"substrate/runtime",
|
"substrate/runtime",
|
||||||
"substrate/consensus",
|
"substrate/consensus",
|
||||||
"substrate/node"
|
"substrate/node",
|
||||||
|
|
||||||
|
"contracts/multisig",
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|||||||
37
contracts/multisig/Cargo.toml
Normal file
37
contracts/multisig/Cargo.toml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[package]
|
||||||
|
name = "multisig-serai"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "An ink! tracker for Serai's current multisig"
|
||||||
|
license = "AGPL-3.0-only"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ink_primitives = { version = "3", default-features = false }
|
||||||
|
ink_metadata = { version = "3", default-features = false, features = ["derive"], optional = true }
|
||||||
|
ink_env = { version = "3", default-features = false }
|
||||||
|
ink_storage = { version = "3", default-features = false }
|
||||||
|
ink_lang = { version = "3", default-features = false }
|
||||||
|
|
||||||
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
scale-info = { version = "2", default-features = false, features = ["derive"], optional = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "multisig"
|
||||||
|
path = "lib.rs"
|
||||||
|
crate-type = [
|
||||||
|
# Used for normal contract Wasm blobs.
|
||||||
|
"cdylib",
|
||||||
|
]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = [
|
||||||
|
"ink_metadata/std",
|
||||||
|
"ink_env/std",
|
||||||
|
"ink_storage/std",
|
||||||
|
"ink_primitives/std",
|
||||||
|
"scale/std",
|
||||||
|
"scale-info/std",
|
||||||
|
]
|
||||||
|
ink-as-dependency = []
|
||||||
184
contracts/multisig/lib.rs
Normal file
184
contracts/multisig/lib.rs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
use ink_lang as ink;
|
||||||
|
use ink_env::{Environment, DefaultEnvironment, AccountId};
|
||||||
|
|
||||||
|
#[ink::chain_extension]
|
||||||
|
pub trait ValidatorsExtension {
|
||||||
|
type ErrorCode = ();
|
||||||
|
|
||||||
|
/// Returns the amount of active validators on the current chain.
|
||||||
|
#[ink(extension = 0, handle_status = false, returns_result = false)]
|
||||||
|
fn active_validators_len() -> u16;
|
||||||
|
|
||||||
|
/// Returns the ID for the current validator set for the current chain.
|
||||||
|
// TODO: Decide if this should be an increasing unsigned integer instead of a hash.
|
||||||
|
#[ink(extension = 1, handle_status = false, returns_result = false)]
|
||||||
|
fn validator_set_id() -> [u8; 32];
|
||||||
|
|
||||||
|
/// Returns if the specified account is an active validator for the current chain.
|
||||||
|
#[ink(extension = 2, handle_status = false, returns_result = false)]
|
||||||
|
fn is_active_validator(account: &AccountId) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ValidatorEnvironment;
|
||||||
|
impl Environment for ValidatorEnvironment {
|
||||||
|
const MAX_EVENT_TOPICS: usize = <DefaultEnvironment as Environment>::MAX_EVENT_TOPICS;
|
||||||
|
|
||||||
|
type AccountId = <DefaultEnvironment as Environment>::AccountId;
|
||||||
|
type Balance = <DefaultEnvironment as Environment>::Balance;
|
||||||
|
type Hash = <DefaultEnvironment as Environment>::Hash;
|
||||||
|
type BlockNumber = <DefaultEnvironment as Environment>::BlockNumber;
|
||||||
|
type Timestamp = <DefaultEnvironment as Environment>::Timestamp;
|
||||||
|
|
||||||
|
type ChainExtension = ValidatorsExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ink::contract(env = crate::ValidatorEnvironment)]
|
||||||
|
mod multisig {
|
||||||
|
use scale::Encode;
|
||||||
|
|
||||||
|
use ink_storage::{traits::SpreadAllocate, Mapping};
|
||||||
|
use ink_env::{hash::Blake2x256, hash_encoded};
|
||||||
|
|
||||||
|
/// A contract which tracks the current multisig keys.
|
||||||
|
#[ink(storage)]
|
||||||
|
#[derive(SpreadAllocate)]
|
||||||
|
pub struct Multisig {
|
||||||
|
/// Validator set currently holding the multisig.
|
||||||
|
validator_set: [u8; 32],
|
||||||
|
/// Mapping from a curve's index to the multisig's current public key for it.
|
||||||
|
// This is a mapping due to ink's eager loading. Considering we're right now only considering
|
||||||
|
// secp256k1 and Ed25519, it may be notably more efficient to use a Vec here.
|
||||||
|
keys: Mapping<u8, Vec<u8>>,
|
||||||
|
/// Voter + Keys -> Voted already or not
|
||||||
|
voted: Mapping<(AccountId, [u8; 32]), ()>,
|
||||||
|
/// Validator Set + Keys -> Vote Count
|
||||||
|
votes: Mapping<([u8; 32], [u8; 32]), u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Event emitted when a new set of multisig keys is voted on. Only for the first vote on a set
|
||||||
|
// of keys will they be present in this event.
|
||||||
|
#[ink(event)]
|
||||||
|
pub struct Vote {
|
||||||
|
/// Validator who issued the vote.
|
||||||
|
#[ink(topic)]
|
||||||
|
validator: AccountId,
|
||||||
|
/// Validator set for which keys are being generated.
|
||||||
|
#[ink(topic)]
|
||||||
|
validator_set: [u8; 32],
|
||||||
|
/// Hash of the keys voted on.
|
||||||
|
#[ink(topic)]
|
||||||
|
hash: [u8; 32],
|
||||||
|
/// Keys voted on.
|
||||||
|
keys: Vec<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Event emitted when the new keys are fully generated for all curves, having been fully voted
|
||||||
|
/// on.
|
||||||
|
#[ink(event)]
|
||||||
|
pub struct KeyGen {
|
||||||
|
#[ink(topic)]
|
||||||
|
hash: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Multisig error types.
|
||||||
|
#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
|
||||||
|
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
|
||||||
|
pub enum Error {
|
||||||
|
/// Returned if a curve index doesn't have a key registered for it.
|
||||||
|
NonExistentCurve,
|
||||||
|
/// Returned if a non-validator is voting.
|
||||||
|
NotValidator,
|
||||||
|
/// Returned if this validator set already generated keys.
|
||||||
|
AlreadyGeneratedKeys,
|
||||||
|
/// Returned if this validator has already voted for these keys.
|
||||||
|
AlreadyVoted,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Multisig result type.
|
||||||
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
|
impl Multisig {
|
||||||
|
/// Deploys the Multisig contract.
|
||||||
|
#[ink(constructor)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ink_lang::utils::initialize_contract(|_| {})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validator set currently holding the multisig.
|
||||||
|
#[ink(message)]
|
||||||
|
pub fn validator_set(&self) -> [u8; 32] {
|
||||||
|
self.validator_set
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the key currently in-use for a given curve ID. This is then bound to a given chain
|
||||||
|
/// by applying a personalized additive offset, as done by the processor. Each chain then has
|
||||||
|
/// its own way of receiving funds to these keys, leaving this not for usage by wallets, nor
|
||||||
|
/// the processor which is expected to track events for this information. This is really solely
|
||||||
|
/// for debugging purposes.
|
||||||
|
#[ink(message)]
|
||||||
|
pub fn key(&self, curve: u8) -> Result<Vec<u8>> {
|
||||||
|
self.keys.get(curve).ok_or(Error::NonExistentCurve)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: voted
|
||||||
|
// TODO: votes
|
||||||
|
|
||||||
|
fn hash<T: Encode>(value: &T) -> [u8; 32] {
|
||||||
|
let mut output = [0; 32];
|
||||||
|
hash_encoded::<Blake2x256, _>(value, &mut output);
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Vote for a given set of keys.
|
||||||
|
#[ink(message)]
|
||||||
|
pub fn vote(&mut self, keys: Vec<Vec<u8>>) -> Result<()> {
|
||||||
|
if keys.len() > 256 {
|
||||||
|
Err(Error::NonExistentCurve)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let validator = self.env().caller();
|
||||||
|
if !self.env().extension().is_active_validator(&validator) {
|
||||||
|
Err(Error::NotValidator)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let validator_set = self.env().extension().validator_set_id();
|
||||||
|
if self.validator_set == validator_set {
|
||||||
|
Err(Error::AlreadyGeneratedKeys)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let keys_hash = Self::hash(&keys);
|
||||||
|
if self.voted.get((validator, keys_hash)).is_some() {
|
||||||
|
Err(Error::AlreadyVoted)?;
|
||||||
|
}
|
||||||
|
self.voted.insert((validator, keys_hash), &());
|
||||||
|
|
||||||
|
let votes = if let Some(votes) = self.votes.get((validator_set, keys_hash)) {
|
||||||
|
self.env().emit_event(Vote { validator, validator_set, hash: keys_hash, keys: vec![] });
|
||||||
|
votes + 1
|
||||||
|
} else {
|
||||||
|
self.env().emit_event(Vote {
|
||||||
|
validator,
|
||||||
|
validator_set,
|
||||||
|
hash: keys_hash,
|
||||||
|
keys: keys.clone(),
|
||||||
|
});
|
||||||
|
1
|
||||||
|
};
|
||||||
|
// We could skip writing this if we've reached consensus, yet best to keep our ducks in a row
|
||||||
|
self.votes.insert((validator_set, keys_hash), &votes);
|
||||||
|
|
||||||
|
// If we've reached consensus, action this.
|
||||||
|
if votes == self.env().extension().active_validators_len() {
|
||||||
|
self.validator_set = validator_set;
|
||||||
|
for (k, key) in keys.iter().enumerate() {
|
||||||
|
self.keys.insert(u8::try_from(k).unwrap(), key);
|
||||||
|
}
|
||||||
|
self.env().emit_event(KeyGen { hash: keys_hash });
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
docs/protocol/Multisig.md
Normal file
27
docs/protocol/Multisig.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Multisig
|
||||||
|
|
||||||
|
The multisig is represented on chain by the `Multisig` contract.
|
||||||
|
|
||||||
|
### `vote(keys: Vec<Vec<u8>>)`
|
||||||
|
|
||||||
|
Lets a validator vote on a set of keys. Once all validators have voted on these
|
||||||
|
keys, it becomes the tracked set of keys for incoming funds.
|
||||||
|
|
||||||
|
The old keys are eligible to still receive transactions for a provided grace
|
||||||
|
period. This means nodes are expected to track and oraclize incoming
|
||||||
|
transactions for both sets of keys. At the end of the grace period, the old keys
|
||||||
|
are dropped from consideration, and all funds are forwarded to the new keys at
|
||||||
|
the next transaction interval for a given chain.
|
||||||
|
|
||||||
|
The old keys are expected to process outbounds until they forward their funds,
|
||||||
|
at which point the new keys are expected to process outbounds.
|
||||||
|
|
||||||
|
Unlike transactions in, which is confirmed as part of the BFT process, a 100%
|
||||||
|
vote is used here. While the BFT process would confirm that keys were generated
|
||||||
|
and enough nodes acknowledge them the wallet would be spendable from, it does
|
||||||
|
not confirm fault tolerance. If the other 33% of nodes failed to receive their
|
||||||
|
key shares somehow, the multisig which is intended to be t-of-n would instead be
|
||||||
|
t-of-t.
|
||||||
|
|
||||||
|
Accordingly, validators are allowed to vote multiple times, and the first key
|
||||||
|
set to receive the necessary votes becomes the new key set.
|
||||||
Reference in New Issue
Block a user