Merge pull request #82 from yrashk/required-signatures
Problem: required_signatures is static
This commit is contained in:
commit
7c429798b3
|
@ -130,7 +130,6 @@ withdraw_confirm = { gas = 3000000 }
|
||||||
#### authorities options
|
#### authorities options
|
||||||
|
|
||||||
- `authorities.account` - all authorities (**required**)
|
- `authorities.account` - all authorities (**required**)
|
||||||
- `authorities.required_signatures` - number of authorities signatures required to consider action final (**required**)
|
|
||||||
|
|
||||||
#### transaction options
|
#### transaction options
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use itertools::Itertools;
|
||||||
|
|
||||||
fn deposits_filter(home: &home::HomeBridge, address: Address) -> FilterBuilder {
|
fn deposits_filter(home: &home::HomeBridge, address: Address) -> FilterBuilder {
|
||||||
let filter = home.events().deposit().create_filter();
|
let filter = home.events().deposit().create_filter();
|
||||||
web3_filter(filter, address)
|
web3_filter(filter, ::std::iter::once(address))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deposit_relay_payload(home: &home::HomeBridge, foreign: &foreign::ForeignBridge, log: Log) -> Result<Bytes> {
|
fn deposit_relay_payload(home: &home::HomeBridge, foreign: &foreign::ForeignBridge, log: Log) -> Result<Bytes> {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use super::BridgeChecked;
|
||||||
|
|
||||||
fn withdraws_filter(foreign: &foreign::ForeignBridge, address: Address) -> FilterBuilder {
|
fn withdraws_filter(foreign: &foreign::ForeignBridge, address: Address) -> FilterBuilder {
|
||||||
let filter = foreign.events().withdraw().create_filter();
|
let filter = foreign.events().withdraw().create_filter();
|
||||||
web3_filter(filter, address)
|
web3_filter(filter, ::std::iter::once(address))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn withdraw_submit_signature_payload(foreign: &foreign::ForeignBridge, withdraw_message: Vec<u8>, signature: H520) -> Bytes {
|
fn withdraw_submit_signature_payload(foreign: &foreign::ForeignBridge, withdraw_message: Vec<u8>, signature: H520) -> Bytes {
|
||||||
|
|
|
@ -19,9 +19,9 @@ use super::BridgeChecked;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
/// returns a filter for `ForeignBridge.CollectedSignatures` events
|
/// returns a filter for `ForeignBridge.CollectedSignatures` events
|
||||||
fn collected_signatures_filter(foreign: &foreign::ForeignBridge, address: Address) -> FilterBuilder {
|
fn collected_signatures_filter<I: IntoIterator<Item = Address>>(foreign: &foreign::ForeignBridge, addresses: I) -> FilterBuilder {
|
||||||
let filter = foreign.events().collected_signatures().create_filter();
|
let filter = foreign.events().collected_signatures().create_filter();
|
||||||
web3_filter(filter, address)
|
web3_filter(filter, addresses)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// payloads for calls to `ForeignBridge.signature` and `ForeignBridge.message`
|
/// payloads for calls to `ForeignBridge.signature` and `ForeignBridge.message`
|
||||||
|
@ -34,7 +34,7 @@ struct RelayAssignment {
|
||||||
message_payload: Bytes,
|
message_payload: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signatures_payload(foreign: &foreign::ForeignBridge, required_signatures: u32, my_address: Address, log: Log) -> error::Result<Option<RelayAssignment>> {
|
fn signatures_payload(foreign: &foreign::ForeignBridge, my_address: Address, log: Log) -> error::Result<Option<RelayAssignment>> {
|
||||||
// convert web3::Log to ethabi::RawLog since ethabi events can
|
// convert web3::Log to ethabi::RawLog since ethabi events can
|
||||||
// only be parsed from the latter
|
// only be parsed from the latter
|
||||||
let raw_log = RawLog {
|
let raw_log = RawLog {
|
||||||
|
@ -48,7 +48,9 @@ fn signatures_payload(foreign: &foreign::ForeignBridge, required_signatures: u32
|
||||||
// someone else will relay this transaction to home.
|
// someone else will relay this transaction to home.
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let signature_payloads = (0..required_signatures).into_iter()
|
|
||||||
|
let required_signatures: U256 = (&foreign.functions().message().input(collected_signatures.number_of_collected_signatures)[4..]).into();
|
||||||
|
let signature_payloads = (0..required_signatures.low_u32()).into_iter()
|
||||||
.map(|index| foreign.functions().signature().input(collected_signatures.message_hash, index))
|
.map(|index| foreign.functions().signature().input(collected_signatures.message_hash, index))
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -83,7 +85,7 @@ pub fn create_withdraw_relay<T: Transport + Clone>(app: Arc<App<T>>, init: &Data
|
||||||
request_timeout: app.config.foreign.request_timeout,
|
request_timeout: app.config.foreign.request_timeout,
|
||||||
poll_interval: app.config.foreign.poll_interval,
|
poll_interval: app.config.foreign.poll_interval,
|
||||||
confirmations: app.config.foreign.required_confirmations,
|
confirmations: app.config.foreign.required_confirmations,
|
||||||
filter: collected_signatures_filter(&app.foreign_bridge, init.foreign_contract_address),
|
filter: collected_signatures_filter(&app.foreign_bridge, vec![init.foreign_contract_address]),
|
||||||
};
|
};
|
||||||
|
|
||||||
WithdrawRelay {
|
WithdrawRelay {
|
||||||
|
@ -120,7 +122,13 @@ impl<T: Transport> Stream for WithdrawRelay<T> {
|
||||||
let contract = self.home_contract.clone();
|
let contract = self.home_contract.clone();
|
||||||
let home = &self.app.config.home;
|
let home = &self.app.config.home;
|
||||||
let t = &self.app.connections.home;
|
let t = &self.app.connections.home;
|
||||||
|
let foreign = &self.app.connections.foreign;
|
||||||
let chain_id = self.home_chain_id;
|
let chain_id = self.home_chain_id;
|
||||||
|
let foreign_bridge = &self.app.foreign_bridge;
|
||||||
|
let foreign_account = self.app.config.foreign.account;
|
||||||
|
let timer = &self.app.timer;
|
||||||
|
let foreign_contract = self.foreign_contract;
|
||||||
|
let foreign_request_timeout = self.app.config.foreign.request_timeout;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let next_state = match self.state {
|
let next_state = match self.state {
|
||||||
|
@ -129,14 +137,10 @@ impl<T: Transport> Stream for WithdrawRelay<T> {
|
||||||
info!("got {} new signed withdraws to relay", item.logs.len());
|
info!("got {} new signed withdraws to relay", item.logs.len());
|
||||||
let assignments = item.logs
|
let assignments = item.logs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|log| {
|
.map(|log| signatures_payload(
|
||||||
info!("collected signature is ready for relay: tx hash: {}", log.transaction_hash.unwrap());
|
foreign_bridge,
|
||||||
signatures_payload(
|
foreign_account,
|
||||||
&self.app.foreign_bridge,
|
log))
|
||||||
self.app.config.authorities.required_signatures,
|
|
||||||
self.app.config.foreign.account,
|
|
||||||
log)
|
|
||||||
})
|
|
||||||
.collect::<error::Result<Vec<_>>>()?;
|
.collect::<error::Result<Vec<_>>>()?;
|
||||||
|
|
||||||
let (signatures, messages): (Vec<_>, Vec<_>) = assignments.into_iter()
|
let (signatures, messages): (Vec<_>, Vec<_>) = assignments.into_iter()
|
||||||
|
@ -146,9 +150,9 @@ impl<T: Transport> Stream for WithdrawRelay<T> {
|
||||||
|
|
||||||
let message_calls = messages.into_iter()
|
let message_calls = messages.into_iter()
|
||||||
.map(|payload| {
|
.map(|payload| {
|
||||||
self.app.timer.timeout(
|
timer.timeout(
|
||||||
api::call(&self.app.connections.foreign, self.foreign_contract.clone(), payload),
|
api::call(foreign, foreign_contract.clone(), payload),
|
||||||
self.app.config.foreign.request_timeout)
|
foreign_request_timeout)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -156,9 +160,9 @@ impl<T: Transport> Stream for WithdrawRelay<T> {
|
||||||
.map(|payloads| {
|
.map(|payloads| {
|
||||||
payloads.into_iter()
|
payloads.into_iter()
|
||||||
.map(|payload| {
|
.map(|payload| {
|
||||||
self.app.timer.timeout(
|
timer.timeout(
|
||||||
api::call(&self.app.connections.foreign, self.foreign_contract.clone(), payload),
|
api::call(foreign, foreign_contract.clone(), payload),
|
||||||
self.app.config.foreign.request_timeout)
|
foreign_request_timeout)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
})
|
})
|
||||||
|
@ -271,11 +275,11 @@ mod tests {
|
||||||
let foreign = foreign::ForeignBridge::default();
|
let foreign = foreign::ForeignBridge::default();
|
||||||
let my_address = "aff3454fce5edbc8cca8697c15331677e6ebcccc".into();
|
let my_address = "aff3454fce5edbc8cca8697c15331677e6ebcccc".into();
|
||||||
|
|
||||||
let data = "000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc00000000000000000000000000000000000000000000000000000000000000f0".from_hex().unwrap();
|
let data = "000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc00000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000002".from_hex().unwrap();
|
||||||
|
|
||||||
let log = Log {
|
let log = Log {
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
topics: vec!["eb043d149eedb81369bec43d4c3a3a53087debc88d2525f13bfaa3eecda28b5c".into()],
|
topics: vec!["415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d7237".into()],
|
||||||
transaction_hash: Some("884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364".into()),
|
transaction_hash: Some("884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364".into()),
|
||||||
address: Address::zero(),
|
address: Address::zero(),
|
||||||
block_hash: None,
|
block_hash: None,
|
||||||
|
@ -287,7 +291,7 @@ mod tests {
|
||||||
removed: None,
|
removed: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let assignment = signatures_payload(&foreign, 2, my_address, log).unwrap().unwrap();
|
let assignment = signatures_payload(&foreign, my_address, log).unwrap().unwrap();
|
||||||
let expected_message: Bytes = "490a32c600000000000000000000000000000000000000000000000000000000000000f0".from_hex().unwrap().into();
|
let expected_message: Bytes = "490a32c600000000000000000000000000000000000000000000000000000000000000f0".from_hex().unwrap().into();
|
||||||
let expected_signatures: Vec<Bytes> = vec![
|
let expected_signatures: Vec<Bytes> = vec![
|
||||||
"1812d99600000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap().into(),
|
"1812d99600000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap().into(),
|
||||||
|
@ -302,11 +306,11 @@ mod tests {
|
||||||
let foreign = foreign::ForeignBridge::default();
|
let foreign = foreign::ForeignBridge::default();
|
||||||
let my_address = "aff3454fce5edbc8cca8697c15331677e6ebcccd".into();
|
let my_address = "aff3454fce5edbc8cca8697c15331677e6ebcccd".into();
|
||||||
|
|
||||||
let data = "000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc00000000000000000000000000000000000000000000000000000000000000f0".from_hex().unwrap();
|
let data = "000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc00000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000002".from_hex().unwrap();
|
||||||
|
|
||||||
let log = Log {
|
let log = Log {
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
topics: vec!["eb043d149eedb81369bec43d4c3a3a53087debc88d2525f13bfaa3eecda28b5c".into()],
|
topics: vec!["415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d7237".into()],
|
||||||
transaction_hash: Some("884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364".into()),
|
transaction_hash: Some("884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364".into()),
|
||||||
address: Address::zero(),
|
address: Address::zero(),
|
||||||
block_hash: None,
|
block_hash: None,
|
||||||
|
@ -318,7 +322,7 @@ mod tests {
|
||||||
removed: None,
|
removed: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let assignment = signatures_payload(&foreign, 2, my_address, log).unwrap();
|
let assignment = signatures_payload(&foreign, my_address, log).unwrap();
|
||||||
assert_eq!(None, assignment);
|
assert_eq!(None, assignment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ impl Config {
|
||||||
authorities: Authorities {
|
authorities: Authorities {
|
||||||
#[cfg(feature = "deploy")]
|
#[cfg(feature = "deploy")]
|
||||||
accounts: config.authorities.accounts,
|
accounts: config.authorities.accounts,
|
||||||
|
#[cfg(feature = "deploy")]
|
||||||
required_signatures: config.authorities.required_signatures,
|
required_signatures: config.authorities.required_signatures,
|
||||||
},
|
},
|
||||||
txs: config.transactions.map(Transactions::from_load_struct).unwrap_or_default(),
|
txs: config.transactions.map(Transactions::from_load_struct).unwrap_or_default(),
|
||||||
|
@ -220,6 +221,7 @@ pub struct ContractConfig {
|
||||||
pub struct Authorities {
|
pub struct Authorities {
|
||||||
#[cfg(feature = "deploy")]
|
#[cfg(feature = "deploy")]
|
||||||
pub accounts: Vec<Address>,
|
pub accounts: Vec<Address>,
|
||||||
|
#[cfg(feature = "deploy")]
|
||||||
pub required_signatures: u32,
|
pub required_signatures: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,6 +327,7 @@ mod load {
|
||||||
#[cfg(feature = "deploy")]
|
#[cfg(feature = "deploy")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub accounts: Vec<Address>,
|
pub accounts: Vec<Address>,
|
||||||
|
#[cfg(feature = "deploy")]
|
||||||
pub required_signatures: u32,
|
pub required_signatures: u32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,7 +406,6 @@ required_signatures = 2
|
||||||
#[cfg(feature = "deploy")]
|
#[cfg(feature = "deploy")]
|
||||||
accounts: vec![
|
accounts: vec![
|
||||||
],
|
],
|
||||||
required_signatures: 2,
|
|
||||||
},
|
},
|
||||||
keystore: "/keys/".into(),
|
keystore: "/keys/".into(),
|
||||||
};
|
};
|
||||||
|
@ -466,7 +468,6 @@ required_signatures = 2
|
||||||
#[cfg(feature = "deploy")]
|
#[cfg(feature = "deploy")]
|
||||||
accounts: vec![
|
accounts: vec![
|
||||||
],
|
],
|
||||||
required_signatures: 2,
|
|
||||||
},
|
},
|
||||||
keystore: "/keys/".into(),
|
keystore: "/keys/".into(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,6 +26,9 @@ error_chain! {
|
||||||
errors {
|
errors {
|
||||||
ShutdownRequested
|
ShutdownRequested
|
||||||
InsufficientFunds
|
InsufficientFunds
|
||||||
|
NoRequiredSignaturesChanged {
|
||||||
|
description("No RequiredSignaturesChanged has been observed")
|
||||||
|
}
|
||||||
// api timeout
|
// api timeout
|
||||||
Timeout(request: &'static str) {
|
Timeout(request: &'static str) {
|
||||||
description("Request timeout"),
|
description("Request timeout"),
|
||||||
|
|
|
@ -11,12 +11,12 @@ fn web3_topic(topic: ethabi::Topic<ethabi::Hash>) -> Option<Vec<H256>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn web3_filter(filter: ethabi::TopicFilter, address: Address) -> FilterBuilder {
|
pub fn web3_filter<I: IntoIterator<Item = Address>>(filter: ethabi::TopicFilter, addresses: I) -> FilterBuilder {
|
||||||
let t0 = web3_topic(filter.topic0);
|
let t0 = web3_topic(filter.topic0);
|
||||||
let t1 = web3_topic(filter.topic1);
|
let t1 = web3_topic(filter.topic1);
|
||||||
let t2 = web3_topic(filter.topic2);
|
let t2 = web3_topic(filter.topic2);
|
||||||
let t3 = web3_topic(filter.topic3);
|
let t3 = web3_topic(filter.topic3);
|
||||||
FilterBuilder::default()
|
FilterBuilder::default()
|
||||||
.address(vec![address])
|
.address(addresses.into_iter().collect())
|
||||||
.topics(t0, t1, t2, t3)
|
.topics(t0, t1, t2, t3)
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,7 +400,7 @@ contract ForeignBridge is BridgeDeploymentAddressStorage,
|
||||||
event Withdraw(address recipient, uint256 value, uint256 homeGasPrice);
|
event Withdraw(address recipient, uint256 value, uint256 homeGasPrice);
|
||||||
|
|
||||||
/// Collected signatures which should be relayed to home chain.
|
/// Collected signatures which should be relayed to home chain.
|
||||||
event CollectedSignatures(address authorityResponsibleForRelay, bytes32 messageHash);
|
event CollectedSignatures(address authorityResponsibleForRelay, bytes32 messageHash, uint256 NumberOfCollectedSignatures);
|
||||||
|
|
||||||
/// Event created when new token address is set up.
|
/// Event created when new token address is set up.
|
||||||
event TokenAddress(address token);
|
event TokenAddress(address token);
|
||||||
|
@ -551,7 +551,7 @@ contract ForeignBridge is BridgeDeploymentAddressStorage,
|
||||||
|
|
||||||
// TODO: this may cause troubles if requiredSignatures len is changed
|
// TODO: this may cause troubles if requiredSignatures len is changed
|
||||||
if (signed == requiredSignatures) {
|
if (signed == requiredSignatures) {
|
||||||
CollectedSignatures(msg.sender, hash);
|
CollectedSignatures(msg.sender, hash, signed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue