From 07d11e050eca0b19ea6267dc1b4a42d76569c215 Mon Sep 17 00:00:00 2001 From: Tomasz Polaczyk Date: Fri, 18 Mar 2022 17:15:09 +0100 Subject: [PATCH] fix(bridge): avoid problems with overloaded functions By ensuring that only one function exists with any given name --- bridges/centralized-ethereum/src/lib.rs | 46 ++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/bridges/centralized-ethereum/src/lib.rs b/bridges/centralized-ethereum/src/lib.rs index fdeb17499..8ac1973c0 100644 --- a/bridges/centralized-ethereum/src/lib.rs +++ b/bridges/centralized-ethereum/src/lib.rs @@ -29,12 +29,40 @@ pub fn create_wrb_contract(eth_client_url: &str, wrb_contract_addr: H160) -> Con let web3 = web3::Web3::new(web3_http); // Why read files at runtime when you can read files at compile time let wrb_contract_abi_json: &[u8] = include_bytes!("../wrb_abi.json"); - let wrb_contract_abi = web3::ethabi::Contract::load(wrb_contract_abi_json) + let mut wrb_contract_abi = web3::ethabi::Contract::load(wrb_contract_abi_json) .map_err(|e| format!("Unable to load WRB contract from ABI: {:?}", e)) .unwrap(); + + // Fix issue #2046, manually select the desired function when multiple candidates have the same name + // https://github.com/witnet/witnet-rust/issues/2046 + hack_fix_functions_with_multiple_definitions(&mut wrb_contract_abi); + Contract::new(web3.eth(), wrb_contract_addr, wrb_contract_abi) } +// The web3 library does not properly support overloaded functions yet, so here we ensure that there +// is no ambiguity and every function has only one possible definition +fn hack_fix_functions_with_multiple_definitions(wrb_contract_abi: &mut web3::ethabi::Contract) { + let functions = wrb_contract_abi + .functions + .get_mut("reportResult") + .expect("no reportResult function in ABI"); + // There are two candidate "reportResult" functions, we want to keep the one with 4 inputs + assert_eq!(functions.len(), 2); + functions.retain(|f| f.inputs.len() == 4); + assert_eq!(functions.len(), 1); + + // Ensure that all functions only have one possible definition + for (function_name, definitions) in &wrb_contract_abi.functions { + assert_eq!( + definitions.len(), + 1, + "function {:?} is duplicated in ABI", + function_name + ); + } +} + /// Check if the witnet node is running pub async fn check_witnet_node_running(witnet_addr: &str) -> Result<(), String> { let (_handle, witnet_client) = TcpSocket::new(witnet_addr).unwrap(); @@ -136,3 +164,19 @@ pub async fn handle_receipt(receipt: &TransactionReceipt) -> Result<(), ()> { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_hack_fix_functions_with_multiple_definitions() { + // The hack_fix_functions_with_multiple_definitions function already does some checks + // internally, so here we call it to ensure the ABI is correct. + let wrb_contract_abi_json: &[u8] = include_bytes!("../wrb_abi.json"); + let mut wrb_contract_abi = web3::ethabi::Contract::load(wrb_contract_abi_json) + .map_err(|e| format!("Unable to load WRB contract from ABI: {:?}", e)) + .unwrap(); + hack_fix_functions_with_multiple_definitions(&mut wrb_contract_abi); + } +}