diff --git a/src/executive.rs b/src/executive.rs index 9452e51a4..fe5be1e06 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -160,7 +160,9 @@ impl<'a> Executive<'a> { code: self.state.code(address).unwrap_or(vec![]), data: t.data.clone(), }; - self.call(¶ms, &mut substate, &mut []) + // TODO: move output upstream + let mut out = vec![]; + self.call(¶ms, &mut substate, BytesRef::Flexible(&mut out)) } }; @@ -172,7 +174,7 @@ impl<'a> Executive<'a> { /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate and the output. /// Returns either gas_left or `evm::Error`. - pub fn call(&mut self, params: &ActionParams, substate: &mut Substate, output: &mut [u8]) -> evm::Result { + pub fn call(&mut self, params: &ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { // at first, transfer value to destination self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); @@ -181,7 +183,7 @@ impl<'a> Executive<'a> { let cost = self.engine.cost_of_builtin(¶ms.address, ¶ms.data); match cost <= params.gas { true => { - self.engine.execute_builtin(¶ms.address, ¶ms.data, output); + self.engine.execute_builtin(¶ms.address, ¶ms.data, &mut output); Ok(params.gas - cost) }, false => Err(evm::Error::OutOfGas) @@ -270,7 +272,7 @@ impl<'a> Executive<'a> { pub enum OutputPolicy<'a> { /// Return reference to fixed sized output. /// Used for message calls. - Return(&'a mut [u8]), + Return(BytesRef<'a>), /// Init new contract as soon as `RETURN` is called. InitContract } @@ -405,7 +407,7 @@ impl<'a> Ext for Externalities<'a> { }; let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); - ex.call(¶ms, self.substate, output).map(|gas_left| { + ex.call(¶ms, self.substate, BytesRef::Fixed(output)).map(|gas_left| { gas + gas_left.low_u64() }) } @@ -416,11 +418,18 @@ impl<'a> Ext for Externalities<'a> { fn ret(&mut self, gas: u64, data: &[u8]) -> Result { match &mut self.output { - &mut OutputPolicy::Return(ref mut slice) => unsafe { + &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { let len = cmp::min(slice.len(), data.len()); ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); Ok(gas) }, + &mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe { + vec.clear(); + vec.reserve(data.len()); + ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); + vec.set_len(data.len()); + Ok(gas) + }, &mut OutputPolicy::InitContract => { let return_cost = data.len() as u64 * self.schedule.create_data_gas as u64; if return_cost > gas { @@ -743,7 +752,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.call(¶ms, &mut substate, &mut []).unwrap() + ex.call(¶ms, &mut substate, BytesRef::Fixed(&mut [])).unwrap() }; assert_eq!(gas_left, U256::from(73_237)); @@ -785,7 +794,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.call(¶ms, &mut substate, &mut []).unwrap() + ex.call(¶ms, &mut substate, BytesRef::Fixed(&mut [])).unwrap() }; assert_eq!(gas_left, U256::from(59_870)); diff --git a/src/tests/executive.rs b/src/tests/executive.rs index 5784141bc..5d9aba05e 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -213,10 +213,11 @@ fn do_json_test(json_data: &[u8]) -> Vec { }).is_none(); let mut substate = Substate::new(); + let mut output = vec![]; // execute let res = { - let ex = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate, OutputPolicy::Return(&mut [])); + let ex = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate, OutputPolicy::Return(BytesRef::Flexible(&mut output))); let mut test_ext = TestExt::new(ex); let evm = Factory::create(); evm.exec(¶ms, &mut test_ext) @@ -226,9 +227,10 @@ fn do_json_test(json_data: &[u8]) -> Vec { match res { Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."), Ok(gas_left) => { + println!("name: {}, gas_left : {:?}, expected: {:?}", name, gas_left, u256_from_json(&test["gas"])); fail_unless(!out_of_gas, "expected to run out of gas."); fail_unless(gas_left == u256_from_json(&test["gas"]), "gas_left is incorrect"); - println!("name: {}, gas_left : {:?}, expected: {:?}", name, gas_left, u256_from_json(&test["gas"])); + fail_unless(output == bytes_from_json(&test["out"]), "output is incorrect"); } } }