Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added init_running contract function #536

Merged
merged 5 commits into from
Apr 3, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use near_sdk::collections::TreeMap;
use near_sdk::log;
use near_sdk::serde::{Deserialize, Serialize};
use near_sdk::{env, near_bindgen, AccountId, PanicOnDefault, Promise, PromiseOrValue, PublicKey};
use primitives::ParticipantInfo;
use primitives::{CandidateInfo, Candidates, Participants, PkVotes, Votes};
use std::collections::{BTreeMap, HashSet};

Expand Down Expand Up @@ -72,6 +73,36 @@ impl MpcContract {
}
}

// This function can be used to transfer the MPC network to a new contract.
#[init]
pub fn init_running(
epoch: u64,
participants: BTreeMap<AccountId, ParticipantInfo>,
threshold: usize,
public_key: PublicKey,
) -> Self {
log!(
"init_running: signer={}, epoch={}, participants={}, threshold={}, public_key={:?}",
env::signer_account_id(),
epoch,
serde_json::to_string(&participants).unwrap(),
threshold,
public_key
);
MpcContract {
protocol_state: ProtocolContractState::Running(RunningContractState {
epoch,
participants: Participants { participants },
threshold,
public_key,
candidates: Candidates::new(),
join_votes: Votes::new(),
leave_votes: Votes::new(),
}),
pending_requests: TreeMap::new(b"m"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens to the pending requests in old contract?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not move old requests to the new contract since they will be outdated while you transfer them. Nothing bad will happen if nodes try to push signatures for a non-existent payload.
Votes are not transferred either.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would they be outdated? I think it's still fair to maintain these requests though otherwise clients will not be able to tell where their signature went (especially when the NEP lands). We should at the very least report back an error somehow

Copy link
Collaborator Author

@volovyks volovyks Mar 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They will get an error from the old contract. These requests are short-lived and contract migration happens rarely. Also, nodes will need to change the contract manually and that will take more than 8 seconds. We will have some downtime.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may have a more complex design, like a voting mechanism for the "next" contract. But I do not think that is necessary now. This function is mostly for emergencies.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About moving requests from contract to contract. That is not possible with the current design. We are targeting Sync calls only. Each request must be deleted from the queue in the same sign it was added with. Manually added requests will stay there forever.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah this is fine for now as a emergency lever, but ideally we shouldn't be changing contracts. For the error, I'm talking about not just contract-level errors, but applications that are currently relying on indexer to check whether or not a signature has come in. Those applications will forever wait, which isn't good

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the current design, nobody will wait for a signature in an async way. Even if we change the design in the future, such applications should have their timeout.

I agree that we should avoid moving from contract to contract since that is a breaking change for all the clients.
We should be able to handle all the breaking changes in the same contract without moving to a new one.

When adding this function, I was mostly thinking about situations, when we lock the contract to make sure it can not be updated. And then if needed, we can move to another contract using this function.

Should we introduce another contract that will redirect sign calls to the current version of the real MPC contract?
We will control such a contract by setting the current MPC contract ID each time we change it. Loosing this key will not introduce any security threats.
At the same time, all versions of the MPC contract will be locked to prevent all sorts of attacks with stolen contract keys.

}
}

pub fn state(self) -> ProtocolContractState {
self.protocol_state
}
Expand Down
Loading