SecretStore: publish key only if requested through contract
This commit is contained in:
parent
989f2a0542
commit
333e0e1637
@ -1,6 +1,8 @@
|
||||
[
|
||||
{"constant":true,"inputs":[],"name":"serverKeyGenerationRequestsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"authority","type":"address"},{"name":"index","type":"uint256"}],"name":"getServerKeyGenerationRequest","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"uint256"},{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getServerKeyId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"serverKeyPublic","type":"bytes"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"serverKeyGenerated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"serverKeyId","type":"bytes32"}],"name":"getServerKeyThreshold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"authority","type":"address"}],"name":"getServerKeyConfirmationStatus","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},
|
||||
{"anonymous":false,"inputs":[{"indexed":true,"name":"serverKeyId","type":"bytes32"},{"indexed":true,"name":"threshold","type":"uint256"}],"name":"ServerKeyRequested","type":"event"}
|
||||
]
|
@ -187,10 +187,30 @@ impl ServiceContract for OnChainServiceContract {
|
||||
}
|
||||
|
||||
fn publish_server_key(&self, server_key_id: &ServerKeyId, server_key: &Public) -> Result<(), String> {
|
||||
// only publish if contract address is set && client is online
|
||||
let contract = self.contract.read();
|
||||
if contract.address == Default::default() {
|
||||
// it is not an error, because key could be generated even without contract
|
||||
return Ok(());
|
||||
}
|
||||
let client = match self.client.upgrade() {
|
||||
Some(client) => client,
|
||||
None => return Err("client is required to publish key".into()),
|
||||
};
|
||||
|
||||
// only publish key if contract waits for publication
|
||||
// failing is ok here - it could be that enough confirmations have been recevied
|
||||
// or key has been requested using HTTP API
|
||||
let do_call = |a, d| future::done(client.call_contract(BlockId::Latest, a, d));
|
||||
let self_address = public_to_address(self.self_key_pair.public());
|
||||
if contract.get_server_key_confirmation_status(&do_call, server_key_id.clone(), self_address).wait().unwrap_or(false) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// prepare transaction data
|
||||
let server_key_hash = keccak(server_key);
|
||||
let signed_server_key = self.self_key_pair.sign(&server_key_hash).map_err(|e| format!("{}", e))?;
|
||||
let signed_server_key: Signature = signed_server_key.into_electrum().into();
|
||||
let contract = self.contract.read();
|
||||
let transaction_data = contract.encode_server_key_generated_input(server_key_id.clone(),
|
||||
server_key.to_vec(),
|
||||
signed_server_key.v(),
|
||||
@ -198,13 +218,12 @@ impl ServiceContract for OnChainServiceContract {
|
||||
signed_server_key.s().into()
|
||||
)?;
|
||||
|
||||
// send transaction
|
||||
if contract.address != Default::default() {
|
||||
if let Some(client) = self.client.upgrade() {
|
||||
client.transact_contract(
|
||||
contract.address.clone(),
|
||||
transaction_data
|
||||
).map_err(|e| format!("{}", e))?;
|
||||
} // else we will read this in the next refresh cycle
|
||||
client.transact_contract(
|
||||
contract.address.clone(),
|
||||
transaction_data
|
||||
).map_err(|e| format!("{}", e))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -218,24 +237,27 @@ impl Iterator for PendingRequestsIterator {
|
||||
if self.index >= self.length {
|
||||
return None;
|
||||
}
|
||||
|
||||
let index = self.index.clone();
|
||||
self.index = self.index + 1.into();
|
||||
|
||||
let self_address = public_to_address(self.self_key_pair.public());
|
||||
let do_call = |a, d| future::done(self.client.call_contract(BlockId::Latest, a, d));
|
||||
let key_generation_request = self.contract.get_server_key_generation_request(&do_call,
|
||||
public_to_address(self.self_key_pair.public()),
|
||||
(self.index - 1.into()).clone().into()).wait();
|
||||
let (server_key_id, threshold, is_confirmed) = match key_generation_request {
|
||||
Ok((server_key_id, threshold, is_confirmed)) => {
|
||||
(server_key_id, threshold, is_confirmed)
|
||||
},
|
||||
Err(error) => {
|
||||
warn!(target: "secretstore", "{}: call to get_server_key_generation_request failed: {}",
|
||||
self.contract.get_server_key_id(&do_call, index).wait()
|
||||
.and_then(|server_key_id|
|
||||
self.contract.get_server_key_threshold(&do_call, server_key_id.clone()).wait()
|
||||
.map(|threshold| (server_key_id, threshold)))
|
||||
.and_then(|(server_key_id, threshold)|
|
||||
self.contract.get_server_key_confirmation_status(&do_call, server_key_id.clone(), self_address).wait()
|
||||
.map(|is_confirmed| (server_key_id, threshold, is_confirmed)))
|
||||
.map(|(server_key_id, threshold, is_confirmed)|
|
||||
Some((is_confirmed, ServiceTask::GenerateServerKey(server_key_id, threshold.into()))))
|
||||
.map_err(|error| {
|
||||
warn!(target: "secretstore", "{}: reading service contract request failed: {}",
|
||||
self.self_key_pair.public(), error);
|
||||
return None;
|
||||
},
|
||||
};
|
||||
|
||||
Some((is_confirmed, ServiceTask::GenerateServerKey(server_key_id, threshold.into())))
|
||||
()
|
||||
})
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,9 +336,10 @@ impl ChainNotify for ServiceContractListener {
|
||||
return;
|
||||
}
|
||||
|
||||
let reason = "enacted.len() != 0; qed";
|
||||
self.process_service_contract_events(
|
||||
enacted.first().expect("TODO").clone(),
|
||||
enacted.last().expect("TODO").clone());
|
||||
enacted.first().expect(reason).clone(),
|
||||
enacted.last().expect(reason).clone());
|
||||
|
||||
// schedule retry if received enough blocks since last retry
|
||||
// it maybe inaccurate when switching syncing/synced states, but that's ok
|
||||
@ -351,8 +352,6 @@ impl ChainNotify for ServiceContractListener {
|
||||
|
||||
impl ClusterSessionsListener<GenerationSession> for ServiceContractListener {
|
||||
fn on_session_removed(&self, session: Arc<GenerationSession>) {
|
||||
// TODO: only start if session started via the contract
|
||||
|
||||
// only publish when the session is started by another node
|
||||
// when it is started by this node, it is published from process_service_task
|
||||
if !is_processed_by_this_key_server(&*self.data.key_server_set, &*self.data.self_key_pair, &session.id()) {
|
||||
|
Loading…
Reference in New Issue
Block a user