diff --git a/README.md b/README.md index 99ec030..12ead3e 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,6 @@ withdraw_confirm = { gas = 3000000 } #### authorities options - `authorities.account` - all authorities (**required**) -- `authorities.required_signatures` - number of authorities signatures required to consider action final (**required**) #### transaction options diff --git a/bridge/src/bridge/deposit_relay.rs b/bridge/src/bridge/deposit_relay.rs index dd78966..797e843 100644 --- a/bridge/src/bridge/deposit_relay.rs +++ b/bridge/src/bridge/deposit_relay.rs @@ -16,7 +16,7 @@ use itertools::Itertools; fn deposits_filter(home: &home::HomeBridge, address: Address) -> FilterBuilder { 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 { diff --git a/bridge/src/bridge/withdraw_confirm.rs b/bridge/src/bridge/withdraw_confirm.rs index a287a55..676915b 100644 --- a/bridge/src/bridge/withdraw_confirm.rs +++ b/bridge/src/bridge/withdraw_confirm.rs @@ -17,7 +17,7 @@ use super::BridgeChecked; fn withdraws_filter(foreign: &foreign::ForeignBridge, address: Address) -> FilterBuilder { 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, signature: H520) -> Bytes { diff --git a/bridge/src/bridge/withdraw_relay.rs b/bridge/src/bridge/withdraw_relay.rs index e79819b..a5a7b5b 100644 --- a/bridge/src/bridge/withdraw_relay.rs +++ b/bridge/src/bridge/withdraw_relay.rs @@ -19,9 +19,9 @@ use super::BridgeChecked; use itertools::Itertools; /// returns a filter for `ForeignBridge.CollectedSignatures` events -fn collected_signatures_filter(foreign: &foreign::ForeignBridge, address: Address) -> FilterBuilder { +fn collected_signatures_filter>(foreign: &foreign::ForeignBridge, addresses: I) -> FilterBuilder { 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` @@ -34,7 +34,7 @@ struct RelayAssignment { message_payload: Bytes, } -fn signatures_payload(foreign: &foreign::ForeignBridge, required_signatures: u32, my_address: Address, log: Log) -> error::Result> { +fn signatures_payload(foreign: &foreign::ForeignBridge, my_address: Address, log: Log) -> error::Result> { // convert web3::Log to ethabi::RawLog since ethabi events can // only be parsed from the latter 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. 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(Into::into) .collect(); @@ -83,7 +85,7 @@ pub fn create_withdraw_relay(app: Arc>, init: &Data request_timeout: app.config.foreign.request_timeout, poll_interval: app.config.foreign.poll_interval, 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 { @@ -120,7 +122,13 @@ impl Stream for WithdrawRelay { let contract = self.home_contract.clone(); let home = &self.app.config.home; let t = &self.app.connections.home; + let foreign = &self.app.connections.foreign; 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 { let next_state = match self.state { @@ -129,14 +137,10 @@ impl Stream for WithdrawRelay { info!("got {} new signed withdraws to relay", item.logs.len()); let assignments = item.logs .into_iter() - .map(|log| { - info!("collected signature is ready for relay: tx hash: {}", log.transaction_hash.unwrap()); - signatures_payload( - &self.app.foreign_bridge, - self.app.config.authorities.required_signatures, - self.app.config.foreign.account, - log) - }) + .map(|log| signatures_payload( + foreign_bridge, + foreign_account, + log)) .collect::>>()?; let (signatures, messages): (Vec<_>, Vec<_>) = assignments.into_iter() @@ -146,9 +150,9 @@ impl Stream for WithdrawRelay { let message_calls = messages.into_iter() .map(|payload| { - self.app.timer.timeout( - api::call(&self.app.connections.foreign, self.foreign_contract.clone(), payload), - self.app.config.foreign.request_timeout) + timer.timeout( + api::call(foreign, foreign_contract.clone(), payload), + foreign_request_timeout) }) .collect::>(); @@ -156,9 +160,9 @@ impl Stream for WithdrawRelay { .map(|payloads| { payloads.into_iter() .map(|payload| { - self.app.timer.timeout( - api::call(&self.app.connections.foreign, self.foreign_contract.clone(), payload), - self.app.config.foreign.request_timeout) + timer.timeout( + api::call(foreign, foreign_contract.clone(), payload), + foreign_request_timeout) }) .collect::>() }) @@ -271,11 +275,11 @@ mod tests { let foreign = foreign::ForeignBridge::default(); let my_address = "aff3454fce5edbc8cca8697c15331677e6ebcccc".into(); - let data = "000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc00000000000000000000000000000000000000000000000000000000000000f0".from_hex().unwrap(); + let data = "000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc00000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000002".from_hex().unwrap(); let log = Log { data: data.into(), - topics: vec!["eb043d149eedb81369bec43d4c3a3a53087debc88d2525f13bfaa3eecda28b5c".into()], + topics: vec!["415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d7237".into()], transaction_hash: Some("884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364".into()), address: Address::zero(), block_hash: None, @@ -287,7 +291,7 @@ mod tests { 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_signatures: Vec = vec![ "1812d99600000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap().into(), @@ -302,11 +306,11 @@ mod tests { let foreign = foreign::ForeignBridge::default(); let my_address = "aff3454fce5edbc8cca8697c15331677e6ebcccd".into(); - let data = "000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc00000000000000000000000000000000000000000000000000000000000000f0".from_hex().unwrap(); + let data = "000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc00000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000002".from_hex().unwrap(); let log = Log { data: data.into(), - topics: vec!["eb043d149eedb81369bec43d4c3a3a53087debc88d2525f13bfaa3eecda28b5c".into()], + topics: vec!["415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d7237".into()], transaction_hash: Some("884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364".into()), address: Address::zero(), block_hash: None, @@ -318,7 +322,7 @@ mod tests { 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); } } diff --git a/bridge/src/config.rs b/bridge/src/config.rs index b092b28..5d757d0 100644 --- a/bridge/src/config.rs +++ b/bridge/src/config.rs @@ -52,6 +52,7 @@ impl Config { authorities: Authorities { #[cfg(feature = "deploy")] accounts: config.authorities.accounts, + #[cfg(feature = "deploy")] required_signatures: config.authorities.required_signatures, }, txs: config.transactions.map(Transactions::from_load_struct).unwrap_or_default(), @@ -220,6 +221,7 @@ pub struct ContractConfig { pub struct Authorities { #[cfg(feature = "deploy")] pub accounts: Vec
, + #[cfg(feature = "deploy")] pub required_signatures: u32, } @@ -325,6 +327,7 @@ mod load { #[cfg(feature = "deploy")] #[serde(default)] pub accounts: Vec
, + #[cfg(feature = "deploy")] pub required_signatures: u32, } } @@ -403,7 +406,6 @@ required_signatures = 2 #[cfg(feature = "deploy")] accounts: vec![ ], - required_signatures: 2, }, keystore: "/keys/".into(), }; @@ -466,7 +468,6 @@ required_signatures = 2 #[cfg(feature = "deploy")] accounts: vec![ ], - required_signatures: 2, }, keystore: "/keys/".into(), }; diff --git a/bridge/src/error.rs b/bridge/src/error.rs index ce69d0c..24f12d9 100644 --- a/bridge/src/error.rs +++ b/bridge/src/error.rs @@ -26,6 +26,9 @@ error_chain! { errors { ShutdownRequested InsufficientFunds + NoRequiredSignaturesChanged { + description("No RequiredSignaturesChanged has been observed") + } // api timeout Timeout(request: &'static str) { description("Request timeout"), diff --git a/bridge/src/util.rs b/bridge/src/util.rs index dcdb2a4..dc989f8 100644 --- a/bridge/src/util.rs +++ b/bridge/src/util.rs @@ -11,12 +11,12 @@ fn web3_topic(topic: ethabi::Topic) -> Option> { } } -pub fn web3_filter(filter: ethabi::TopicFilter, address: Address) -> FilterBuilder { +pub fn web3_filter>(filter: ethabi::TopicFilter, addresses: I) -> FilterBuilder { let t0 = web3_topic(filter.topic0); let t1 = web3_topic(filter.topic1); let t2 = web3_topic(filter.topic2); let t3 = web3_topic(filter.topic3); FilterBuilder::default() - .address(vec![address]) + .address(addresses.into_iter().collect()) .topics(t0, t1, t2, t3) } diff --git a/contracts/bridge.sol b/contracts/bridge.sol index b4fc86c..184b995 100644 --- a/contracts/bridge.sol +++ b/contracts/bridge.sol @@ -400,7 +400,7 @@ contract ForeignBridge is BridgeDeploymentAddressStorage, event Withdraw(address recipient, uint256 value, uint256 homeGasPrice); /// 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 TokenAddress(address token); @@ -415,11 +415,11 @@ contract ForeignBridge is BridgeDeploymentAddressStorage, require(_requiredSignatures != 0); require(_requiredSignatures <= _authorities.length); requiredSignatures = _requiredSignatures; - + for (uint i = 0; i < _authorities.length; i++) { authorities[_authorities[i]] = true; } - + estimatedGasCostOfWithdraw = _estimatedGasCostOfWithdraw; } @@ -551,7 +551,7 @@ contract ForeignBridge is BridgeDeploymentAddressStorage, // TODO: this may cause troubles if requiredSignatures len is changed if (signed == requiredSignatures) { - CollectedSignatures(msg.sender, hash); + CollectedSignatures(msg.sender, hash, signed); } }