-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
fix conflicts
Showing
29 changed files
with
2,136 additions
and
971 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; | ||
use near_sdk::serde::{Deserialize, Serialize}; | ||
use near_sdk::{AccountId, PublicKey}; | ||
use std::collections::{BTreeMap, HashSet}; | ||
|
||
pub mod hpke { | ||
pub type PublicKey = [u8; 32]; | ||
} | ||
|
||
#[derive( | ||
Serialize, | ||
Deserialize, | ||
BorshDeserialize, | ||
BorshSerialize, | ||
Clone, | ||
Hash, | ||
PartialEq, | ||
Eq, | ||
PartialOrd, | ||
Ord, | ||
Debug, | ||
)] | ||
pub struct ParticipantInfo { | ||
pub account_id: AccountId, | ||
pub url: String, | ||
/// The public key used for encrypting messages. | ||
pub cipher_pk: hpke::PublicKey, | ||
/// The public key used for verifying messages. | ||
pub sign_pk: PublicKey, | ||
} | ||
|
||
impl From<CandidateInfo> for ParticipantInfo { | ||
fn from(candidate_info: CandidateInfo) -> Self { | ||
ParticipantInfo { | ||
account_id: candidate_info.account_id, | ||
url: candidate_info.url, | ||
cipher_pk: candidate_info.cipher_pk, | ||
sign_pk: candidate_info.sign_pk, | ||
} | ||
} | ||
} | ||
|
||
#[derive( | ||
Serialize, | ||
Deserialize, | ||
BorshDeserialize, | ||
BorshSerialize, | ||
Clone, | ||
Hash, | ||
PartialEq, | ||
Eq, | ||
PartialOrd, | ||
Ord, | ||
Debug, | ||
)] | ||
pub struct CandidateInfo { | ||
pub account_id: AccountId, | ||
pub url: String, | ||
/// The public key used for encrypting messages. | ||
pub cipher_pk: hpke::PublicKey, | ||
/// The public key used for verifying messages. | ||
pub sign_pk: PublicKey, | ||
} | ||
|
||
#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Debug, Clone)] | ||
pub struct Participants { | ||
pub participants: BTreeMap<AccountId, ParticipantInfo>, | ||
} | ||
|
||
impl Default for Participants { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl Participants { | ||
pub fn new() -> Self { | ||
Participants { | ||
participants: BTreeMap::new(), | ||
} | ||
} | ||
|
||
pub fn contains_key(&self, account_id: &AccountId) -> bool { | ||
self.participants.contains_key(account_id) | ||
} | ||
|
||
pub fn insert(&mut self, account_id: AccountId, participant_info: ParticipantInfo) { | ||
self.participants.insert(account_id, participant_info); | ||
} | ||
|
||
pub fn remove(&mut self, account_id: &AccountId) { | ||
self.participants.remove(account_id); | ||
} | ||
|
||
pub fn get(&self, account_id: &AccountId) -> Option<&ParticipantInfo> { | ||
self.participants.get(account_id) | ||
} | ||
|
||
pub fn iter(&self) -> impl Iterator<Item = (&AccountId, &ParticipantInfo)> { | ||
self.participants.iter() | ||
} | ||
|
||
pub fn keys(&self) -> impl Iterator<Item = &AccountId> { | ||
self.participants.keys() | ||
} | ||
|
||
pub fn len(&self) -> usize { | ||
self.participants.len() | ||
} | ||
|
||
pub fn is_empty(&self) -> bool { | ||
self.participants.is_empty() | ||
} | ||
} | ||
|
||
#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Debug, Clone)] | ||
pub struct Candidates { | ||
pub candidates: BTreeMap<AccountId, CandidateInfo>, | ||
} | ||
|
||
impl Default for Candidates { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl Candidates { | ||
pub fn new() -> Self { | ||
Candidates { | ||
candidates: BTreeMap::new(), | ||
} | ||
} | ||
|
||
pub fn contains_key(&self, account_id: &AccountId) -> bool { | ||
self.candidates.contains_key(account_id) | ||
} | ||
|
||
pub fn insert(&mut self, account_id: AccountId, candidate: CandidateInfo) { | ||
self.candidates.insert(account_id, candidate); | ||
} | ||
|
||
pub fn remove(&mut self, account_id: &AccountId) { | ||
self.candidates.remove(account_id); | ||
} | ||
|
||
pub fn get(&self, account_id: &AccountId) -> Option<&CandidateInfo> { | ||
self.candidates.get(account_id) | ||
} | ||
|
||
pub fn iter(&self) -> impl Iterator<Item = (&AccountId, &CandidateInfo)> { | ||
self.candidates.iter() | ||
} | ||
} | ||
|
||
#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Debug)] | ||
pub struct Votes { | ||
pub votes: BTreeMap<AccountId, HashSet<AccountId>>, | ||
} | ||
|
||
impl Default for Votes { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl Votes { | ||
pub fn new() -> Self { | ||
Votes { | ||
votes: BTreeMap::new(), | ||
} | ||
} | ||
|
||
pub fn entry(&mut self, account_id: AccountId) -> &mut HashSet<AccountId> { | ||
self.votes.entry(account_id).or_default() | ||
} | ||
} | ||
|
||
#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Debug)] | ||
pub struct PkVotes { | ||
pub votes: BTreeMap<PublicKey, HashSet<AccountId>>, | ||
} | ||
|
||
impl Default for PkVotes { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl PkVotes { | ||
pub fn new() -> Self { | ||
PkVotes { | ||
votes: BTreeMap::new(), | ||
} | ||
} | ||
|
||
pub fn entry(&mut self, public_key: PublicKey) -> &mut HashSet<AccountId> { | ||
self.votes.entry(public_key).or_default() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
terraform { | ||
backend "gcs" { | ||
bucket = "multichain-terraform-prod" | ||
prefix = "state/multichain" | ||
} | ||
|
||
required_providers { | ||
google = { | ||
source = "hashicorp/google" | ||
version = "4.73.0" | ||
} | ||
} | ||
} | ||
|
||
locals { | ||
credentials = var.credentials != null ? var.credentials : file(var.credentials_file) | ||
client_email = jsondecode(local.credentials).client_email | ||
client_id = jsondecode(local.credentials).client_id | ||
|
||
workspace = { | ||
near_rpc = "https://rpc.mainnet.near.org" | ||
} | ||
} | ||
|
||
data "external" "git_checkout" { | ||
program = ["${path.module}/../scripts/get_sha.sh"] | ||
} | ||
|
||
provider "google" { | ||
credentials = local.credentials | ||
|
||
project = var.project | ||
region = var.region | ||
zone = var.zone | ||
} | ||
|
||
/* | ||
* Create brand new service account with basic IAM | ||
*/ | ||
resource "google_service_account" "service_account" { | ||
account_id = "multichain-mainnet" | ||
display_name = "Multichain mainnet Account" | ||
} | ||
|
||
resource "google_service_account_iam_binding" "serivce-account-iam" { | ||
service_account_id = google_service_account.service_account.name | ||
role = "roles/iam.serviceAccountUser" | ||
|
||
members = [ | ||
"serviceAccount:${local.client_email}", | ||
] | ||
} | ||
|
||
/* | ||
* Ensure service account has access to Secret Manager variables | ||
*/ | ||
resource "google_secret_manager_secret_iam_member" "account_sk_secret_access" { | ||
count = length(var.node_configs) | ||
|
||
secret_id = var.node_configs[count.index].account_sk_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "cipher_sk_secret_access" { | ||
count = length(var.node_configs) | ||
|
||
secret_id = var.node_configs[count.index].cipher_sk_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "aws_access_key_secret_access" { | ||
secret_id = var.aws_access_key_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "aws_secret_key_secret_access" { | ||
secret_id = var.aws_secret_key_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "sk_share_secret_access" { | ||
count = length(var.node_configs) | ||
|
||
secret_id = var.node_configs[count.index].sk_share_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "sk_share_secret_manager" { | ||
count = length(var.node_configs) | ||
|
||
secret_id = var.node_configs[count.index].sk_share_secret_id | ||
role = "roles/secretmanager.secretVersionManager" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
module "node" { | ||
count = length(var.node_configs) | ||
source = "../modules/multichain" | ||
|
||
service_name = "multichain-mainnet-${count.index}" | ||
project = var.project | ||
region = var.region | ||
service_account_email = google_service_account.service_account.email | ||
docker_image = var.docker_image | ||
|
||
node_id = count.index | ||
near_rpc = local.workspace.near_rpc | ||
mpc_contract_id = var.mpc_contract_id | ||
account = var.node_configs[count.index].account | ||
cipher_pk = var.node_configs[count.index].cipher_pk | ||
indexer_options = var.indexer_options | ||
my_address = var.node_configs[count.index].address | ||
|
||
account_sk_secret_id = var.node_configs[count.index].account_sk_secret_id | ||
cipher_sk_secret_id = var.node_configs[count.index].cipher_sk_secret_id | ||
aws_access_key_secret_id = var.aws_access_key_secret_id | ||
aws_secret_key_secret_id = var.aws_secret_key_secret_id | ||
sk_share_secret_id = var.node_configs[count.index].sk_share_secret_id | ||
|
||
depends_on = [ | ||
google_secret_manager_secret_iam_member.account_sk_secret_access, | ||
google_secret_manager_secret_iam_member.cipher_sk_secret_access, | ||
google_secret_manager_secret_iam_member.aws_access_key_secret_access, | ||
google_secret_manager_secret_iam_member.aws_secret_key_secret_access, | ||
google_secret_manager_secret_iam_member.sk_share_secret_access, | ||
google_secret_manager_secret_iam_member.sk_share_secret_manager | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
variable "env" { | ||
} | ||
|
||
variable "project" { | ||
} | ||
|
||
variable "credentials_file" { | ||
default = null | ||
} | ||
|
||
variable "credentials" { | ||
default = null | ||
} | ||
|
||
variable "region" { | ||
default = "us-east1" | ||
} | ||
|
||
variable "zone" { | ||
default = "us-east1-c" | ||
} | ||
|
||
variable "docker_image" { | ||
type = string | ||
} | ||
|
||
variable "mpc_contract_id" { | ||
type = string | ||
} | ||
|
||
variable "indexer_options" { | ||
type = object({ | ||
s3_bucket = string | ||
s3_region = string | ||
s3_url = string | ||
start_block_height = number | ||
}) | ||
} | ||
|
||
variable "node_configs" { | ||
type = list(object({ | ||
account = string | ||
cipher_pk = string | ||
address = string | ||
account_sk_secret_id = string | ||
cipher_sk_secret_id = string | ||
sk_share_secret_id = string | ||
})) | ||
} | ||
|
||
variable "aws_access_key_secret_id" { | ||
type = string | ||
} | ||
|
||
variable "aws_secret_key_secret_id" { | ||
type = string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
terraform { | ||
backend "gcs" { | ||
bucket = "multichain-terraform-prod" | ||
prefix = "state/multichain" | ||
} | ||
|
||
required_providers { | ||
google = { | ||
source = "hashicorp/google" | ||
version = "4.73.0" | ||
} | ||
} | ||
} | ||
|
||
locals { | ||
credentials = var.credentials != null ? var.credentials : file(var.credentials_file) | ||
client_email = jsondecode(local.credentials).client_email | ||
client_id = jsondecode(local.credentials).client_id | ||
|
||
workspace = { | ||
near_rpc = "https://rpc.testnet.near.org" | ||
} | ||
} | ||
|
||
data "external" "git_checkout" { | ||
program = ["${path.module}/../scripts/get_sha.sh"] | ||
} | ||
|
||
provider "google" { | ||
credentials = local.credentials | ||
|
||
project = var.project | ||
region = var.region | ||
zone = var.zone | ||
} | ||
|
||
/* | ||
* Create brand new service account with basic IAM | ||
*/ | ||
resource "google_service_account" "service_account" { | ||
account_id = "multichain-testnet" | ||
display_name = "Multichain testnet Account" | ||
} | ||
|
||
resource "google_service_account_iam_binding" "serivce-account-iam" { | ||
service_account_id = google_service_account.service_account.name | ||
role = "roles/iam.serviceAccountUser" | ||
|
||
members = [ | ||
"serviceAccount:${local.client_email}", | ||
] | ||
} | ||
|
||
/* | ||
* Ensure service account has access to Secret Manager variables | ||
*/ | ||
resource "google_secret_manager_secret_iam_member" "account_sk_secret_access" { | ||
count = length(var.node_configs) | ||
|
||
secret_id = var.node_configs[count.index].account_sk_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "cipher_sk_secret_access" { | ||
count = length(var.node_configs) | ||
|
||
secret_id = var.node_configs[count.index].cipher_sk_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "aws_access_key_secret_access" { | ||
secret_id = var.aws_access_key_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "aws_secret_key_secret_access" { | ||
secret_id = var.aws_secret_key_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "sk_share_secret_access" { | ||
count = length(var.node_configs) | ||
|
||
secret_id = var.node_configs[count.index].sk_share_secret_id | ||
role = "roles/secretmanager.secretAccessor" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
resource "google_secret_manager_secret_iam_member" "sk_share_secret_manager" { | ||
count = length(var.node_configs) | ||
|
||
secret_id = var.node_configs[count.index].sk_share_secret_id | ||
role = "roles/secretmanager.secretVersionManager" | ||
member = "serviceAccount:${google_service_account.service_account.email}" | ||
} | ||
|
||
module "node" { | ||
count = length(var.node_configs) | ||
source = "../modules/multichain" | ||
|
||
service_name = "multichain-testnet-${count.index}" | ||
project = var.project | ||
region = var.region | ||
service_account_email = google_service_account.service_account.email | ||
docker_image = var.docker_image | ||
|
||
node_id = count.index | ||
near_rpc = local.workspace.near_rpc | ||
mpc_contract_id = var.mpc_contract_id | ||
account = var.node_configs[count.index].account | ||
cipher_pk = var.node_configs[count.index].cipher_pk | ||
indexer_options = var.indexer_options | ||
my_address = var.node_configs[count.index].address | ||
|
||
account_sk_secret_id = var.node_configs[count.index].account_sk_secret_id | ||
cipher_sk_secret_id = var.node_configs[count.index].cipher_sk_secret_id | ||
aws_access_key_secret_id = var.aws_access_key_secret_id | ||
aws_secret_key_secret_id = var.aws_secret_key_secret_id | ||
sk_share_secret_id = var.node_configs[count.index].sk_share_secret_id | ||
|
||
depends_on = [ | ||
google_secret_manager_secret_iam_member.account_sk_secret_access, | ||
google_secret_manager_secret_iam_member.cipher_sk_secret_access, | ||
google_secret_manager_secret_iam_member.aws_access_key_secret_access, | ||
google_secret_manager_secret_iam_member.aws_secret_key_secret_access, | ||
google_secret_manager_secret_iam_member.sk_share_secret_access, | ||
google_secret_manager_secret_iam_member.sk_share_secret_manager | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
variable "env" { | ||
} | ||
|
||
variable "project" { | ||
} | ||
|
||
variable "credentials_file" { | ||
default = null | ||
} | ||
|
||
variable "credentials" { | ||
default = null | ||
} | ||
|
||
variable "region" { | ||
default = "us-east1" | ||
} | ||
|
||
variable "zone" { | ||
default = "us-east1-c" | ||
} | ||
|
||
variable "docker_image" { | ||
type = string | ||
} | ||
|
||
variable "mpc_contract_id" { | ||
type = string | ||
} | ||
|
||
variable "indexer_options" { | ||
type = object({ | ||
s3_bucket = string | ||
s3_region = string | ||
s3_url = string | ||
start_block_height = number | ||
}) | ||
} | ||
|
||
variable "node_configs" { | ||
type = list(object({ | ||
account = string | ||
cipher_pk = string | ||
address = string | ||
account_sk_secret_id = string | ||
cipher_sk_secret_id = string | ||
sk_share_secret_id = string | ||
})) | ||
} | ||
|
||
variable "aws_access_key_secret_id" { | ||
type = string | ||
} | ||
|
||
variable "aws_secret_key_secret_id" { | ||
type = string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
pub mod primitives; | ||
|
||
use crate::types::PublicKey; | ||
use crate::util::NearPublicKeyExt; | ||
use mpc_contract::ProtocolContractState; | ||
use near_primitives::types::AccountId; | ||
use serde::{Deserialize, Serialize}; | ||
use std::{collections::HashSet, str::FromStr}; | ||
|
||
use self::primitives::{Candidates, Participants, PkVotes, Votes}; | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct InitializingContractState { | ||
pub participants: Participants, | ||
pub threshold: usize, | ||
pub pk_votes: PkVotes, | ||
} | ||
|
||
impl From<mpc_contract::InitializingContractState> for InitializingContractState { | ||
fn from(value: mpc_contract::InitializingContractState) -> Self { | ||
InitializingContractState { | ||
participants: value.participants.into(), | ||
threshold: value.threshold, | ||
pk_votes: value.pk_votes.into(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct RunningContractState { | ||
pub epoch: u64, | ||
pub participants: Participants, | ||
pub threshold: usize, | ||
pub public_key: PublicKey, | ||
pub candidates: Candidates, | ||
pub join_votes: Votes, | ||
pub leave_votes: Votes, | ||
} | ||
|
||
impl From<mpc_contract::RunningContractState> for RunningContractState { | ||
fn from(value: mpc_contract::RunningContractState) -> Self { | ||
RunningContractState { | ||
epoch: value.epoch, | ||
participants: value.participants.into(), | ||
threshold: value.threshold, | ||
public_key: value.public_key.into_affine_point(), | ||
candidates: value.candidates.into(), | ||
join_votes: value.join_votes.into(), | ||
leave_votes: value.leave_votes.into(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct ResharingContractState { | ||
pub old_epoch: u64, | ||
pub old_participants: Participants, | ||
pub new_participants: Participants, | ||
pub threshold: usize, | ||
pub public_key: PublicKey, | ||
pub finished_votes: HashSet<AccountId>, | ||
} | ||
|
||
impl From<mpc_contract::ResharingContractState> for ResharingContractState { | ||
fn from(contract_state: mpc_contract::ResharingContractState) -> Self { | ||
ResharingContractState { | ||
old_epoch: contract_state.old_epoch, | ||
old_participants: contract_state.old_participants.into(), | ||
new_participants: contract_state.new_participants.into(), | ||
threshold: contract_state.threshold, | ||
public_key: contract_state.public_key.into_affine_point(), | ||
finished_votes: contract_state | ||
.finished_votes | ||
.into_iter() | ||
.map(|acc_id| AccountId::from_str(acc_id.as_ref()).unwrap()) | ||
.collect(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum ProtocolState { | ||
Initializing(InitializingContractState), | ||
Running(RunningContractState), | ||
Resharing(ResharingContractState), | ||
} | ||
|
||
impl ProtocolState { | ||
pub fn participants(&self) -> &Participants { | ||
match self { | ||
ProtocolState::Initializing(InitializingContractState { participants, .. }) => { | ||
participants | ||
} | ||
ProtocolState::Running(RunningContractState { participants, .. }) => participants, | ||
ProtocolState::Resharing(ResharingContractState { | ||
old_participants, .. | ||
}) => old_participants, | ||
} | ||
} | ||
|
||
pub fn public_key(&self) -> Option<&PublicKey> { | ||
match self { | ||
ProtocolState::Initializing { .. } => None, | ||
ProtocolState::Running(RunningContractState { public_key, .. }) => Some(public_key), | ||
ProtocolState::Resharing(ResharingContractState { public_key, .. }) => Some(public_key), | ||
} | ||
} | ||
|
||
pub fn threshold(&self) -> usize { | ||
match self { | ||
ProtocolState::Initializing(InitializingContractState { threshold, .. }) => *threshold, | ||
ProtocolState::Running(RunningContractState { threshold, .. }) => *threshold, | ||
ProtocolState::Resharing(ResharingContractState { threshold, .. }) => *threshold, | ||
} | ||
} | ||
} | ||
|
||
impl TryFrom<ProtocolContractState> for ProtocolState { | ||
type Error = (); | ||
|
||
fn try_from(value: ProtocolContractState) -> Result<Self, Self::Error> { | ||
match value { | ||
ProtocolContractState::Initializing(state) => { | ||
Ok(ProtocolState::Initializing(state.into())) | ||
} | ||
ProtocolContractState::Running(state) => Ok(ProtocolState::Running(state.into())), | ||
ProtocolContractState::Resharing(state) => Ok(ProtocolState::Resharing(state.into())), | ||
ProtocolContractState::NotInitialized => Err(()), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
use cait_sith::protocol::Participant; | ||
use mpc_keys::hpke; | ||
use near_primitives::{borsh::BorshDeserialize, types::AccountId}; | ||
use serde::{Deserialize, Serialize}; | ||
use std::{ | ||
collections::{BTreeMap, HashSet}, | ||
str::FromStr, | ||
}; | ||
|
||
type ParticipantId = u32; | ||
|
||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] | ||
pub struct ParticipantInfo { | ||
pub id: ParticipantId, | ||
pub account_id: AccountId, | ||
pub url: String, | ||
/// The public key used for encrypting messages. | ||
pub cipher_pk: hpke::PublicKey, | ||
/// The public key used for verifying messages. | ||
pub sign_pk: near_crypto::PublicKey, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] | ||
pub struct Participants { | ||
pub participants: BTreeMap<Participant, ParticipantInfo>, | ||
} | ||
|
||
impl From<mpc_contract::primitives::Participants> for Participants { | ||
fn from(contract_participants: mpc_contract::primitives::Participants) -> Self { | ||
Participants { | ||
// take position of participant in contract_participants as id for participants | ||
participants: contract_participants | ||
.participants | ||
.into_iter() | ||
.enumerate() | ||
.map(|(participant_id, participant)| { | ||
let contract_participant_info = participant.1; | ||
( | ||
Participant::from(participant_id as ParticipantId), | ||
ParticipantInfo { | ||
id: participant_id as ParticipantId, | ||
account_id: AccountId::from_str( | ||
contract_participant_info.account_id.as_ref(), | ||
) | ||
.unwrap(), | ||
url: contract_participant_info.url, | ||
cipher_pk: hpke::PublicKey::from_bytes( | ||
&contract_participant_info.cipher_pk, | ||
), | ||
sign_pk: BorshDeserialize::try_from_slice( | ||
contract_participant_info.sign_pk.as_bytes(), | ||
) | ||
.unwrap(), | ||
}, | ||
) | ||
}) | ||
.collect(), | ||
} | ||
} | ||
} | ||
|
||
impl IntoIterator for Participants { | ||
type Item = (Participant, ParticipantInfo); | ||
type IntoIter = std::collections::btree_map::IntoIter<Participant, ParticipantInfo>; | ||
|
||
fn into_iter(self) -> Self::IntoIter { | ||
self.participants.into_iter() | ||
} | ||
} | ||
|
||
impl Participants { | ||
pub fn get(&self, id: &Participant) -> Option<&ParticipantInfo> { | ||
self.participants.get(id) | ||
} | ||
|
||
pub fn contains_key(&self, id: &Participant) -> bool { | ||
self.participants.contains_key(id) | ||
} | ||
|
||
pub fn keys(&self) -> impl Iterator<Item = &Participant> { | ||
self.participants.keys() | ||
} | ||
|
||
pub fn iter(&self) -> impl Iterator<Item = (&Participant, &ParticipantInfo)> { | ||
self.participants.iter() | ||
} | ||
|
||
pub fn find_participant(&self, account_id: &AccountId) -> Option<Participant> { | ||
self.participants | ||
.iter() | ||
.find(|(_, participant_info)| participant_info.account_id == *account_id) | ||
.map(|(participant, _)| *participant) | ||
} | ||
|
||
pub fn find_participant_info(&self, account_id: &AccountId) -> Option<&ParticipantInfo> { | ||
self.participants | ||
.values() | ||
.find(|participant_info| participant_info.account_id == *account_id) | ||
} | ||
|
||
pub fn contains_account_id(&self, account_id: &AccountId) -> bool { | ||
self.participants | ||
.values() | ||
.any(|participant_info| participant_info.account_id == *account_id) | ||
} | ||
|
||
pub fn account_ids(&self) -> Vec<AccountId> { | ||
self.participants | ||
.values() | ||
.map(|participant_info| participant_info.account_id.clone()) | ||
.collect() | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] | ||
pub struct CandidateInfo { | ||
pub account_id: AccountId, | ||
pub url: String, | ||
/// The public key used for encrypting messages. | ||
pub cipher_pk: hpke::PublicKey, | ||
/// The public key used for verifying messages. | ||
pub sign_pk: near_crypto::PublicKey, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug, Clone)] | ||
pub struct Candidates { | ||
pub candidates: BTreeMap<AccountId, CandidateInfo>, | ||
} | ||
|
||
impl Candidates { | ||
pub fn get(&self, id: &AccountId) -> Option<&CandidateInfo> { | ||
self.candidates.get(id) | ||
} | ||
|
||
pub fn contains_key(&self, id: &AccountId) -> bool { | ||
self.candidates.contains_key(id) | ||
} | ||
|
||
pub fn keys(&self) -> impl Iterator<Item = &AccountId> { | ||
self.candidates.keys() | ||
} | ||
|
||
pub fn iter(&self) -> impl Iterator<Item = (&AccountId, &CandidateInfo)> { | ||
self.candidates.iter() | ||
} | ||
|
||
pub fn find_candidate(&self, account_id: &AccountId) -> Option<&CandidateInfo> { | ||
self.candidates.get(account_id) | ||
} | ||
} | ||
|
||
impl From<mpc_contract::primitives::Candidates> for Candidates { | ||
fn from(contract_candidates: mpc_contract::primitives::Candidates) -> Self { | ||
Candidates { | ||
candidates: contract_candidates | ||
.candidates | ||
.into_iter() | ||
.map(|(account_id, candidate_info)| { | ||
( | ||
AccountId::from_str(account_id.as_ref()).unwrap(), | ||
CandidateInfo { | ||
account_id: AccountId::from_str(candidate_info.account_id.as_ref()) | ||
.unwrap(), | ||
url: candidate_info.url, | ||
cipher_pk: hpke::PublicKey::from_bytes(&candidate_info.cipher_pk), | ||
sign_pk: BorshDeserialize::try_from_slice( | ||
candidate_info.sign_pk.as_bytes(), | ||
) | ||
.unwrap(), | ||
}, | ||
) | ||
}) | ||
.collect(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug, Clone)] | ||
pub struct PkVotes { | ||
pub pk_votes: BTreeMap<near_crypto::PublicKey, HashSet<AccountId>>, | ||
} | ||
|
||
impl PkVotes { | ||
pub fn get(&self, id: &near_crypto::PublicKey) -> Option<&HashSet<AccountId>> { | ||
self.pk_votes.get(id) | ||
} | ||
} | ||
|
||
impl From<mpc_contract::primitives::PkVotes> for PkVotes { | ||
fn from(contract_votes: mpc_contract::primitives::PkVotes) -> Self { | ||
PkVotes { | ||
pk_votes: contract_votes | ||
.votes | ||
.into_iter() | ||
.map(|(pk, participants)| { | ||
( | ||
near_crypto::PublicKey::SECP256K1( | ||
near_crypto::Secp256K1PublicKey::try_from(&pk.as_bytes()[1..]).unwrap(), | ||
), | ||
participants | ||
.into_iter() | ||
.map(|acc_id: near_sdk::AccountId| { | ||
AccountId::from_str(acc_id.as_ref()).unwrap() | ||
}) | ||
.collect(), | ||
) | ||
}) | ||
.collect(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct Votes { | ||
pub votes: BTreeMap<AccountId, HashSet<AccountId>>, | ||
} | ||
|
||
impl Votes { | ||
pub fn get(&self, id: &AccountId) -> Option<&HashSet<AccountId>> { | ||
self.votes.get(id) | ||
} | ||
} | ||
|
||
impl From<mpc_contract::primitives::Votes> for Votes { | ||
fn from(contract_votes: mpc_contract::primitives::Votes) -> Self { | ||
Votes { | ||
votes: contract_votes | ||
.votes | ||
.into_iter() | ||
.map(|(account_id, participants)| { | ||
( | ||
AccountId::from_str(account_id.as_ref()).unwrap(), | ||
participants | ||
.into_iter() | ||
.map(|acc_id: near_sdk::AccountId| { | ||
AccountId::from_str(acc_id.as_ref()).unwrap() | ||
}) | ||
.collect(), | ||
) | ||
}) | ||
.collect(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters