Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit ad57684

Browse files
committed
EIP211
1 parent d0312ac commit ad57684

File tree

13 files changed

+118
-54
lines changed

13 files changed

+118
-54
lines changed

ethcore/src/evm/evm.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,53 @@ impl fmt::Display for Error {
9797
/// A specialized version of Result over EVM errors.
9898
pub type Result<T> = ::std::result::Result<T, Error>;
9999

100+
101+
/// Return data buffer. Holds memory from a previous call and a slice into that memory.
102+
#[derive(Debug)]
103+
pub struct ReturnData {
104+
mem: Vec<u8>,
105+
offset: usize,
106+
size: usize,
107+
}
108+
109+
impl ::std::ops::Deref for ReturnData {
110+
type Target = [u8];
111+
fn deref(&self) -> &[u8] {
112+
&self.mem[self.offset..self.offset + self.size]
113+
}
114+
}
115+
116+
impl ReturnData {
117+
/// Create empty `ReturnData`.
118+
pub fn empty() -> Self {
119+
ReturnData {
120+
mem: Vec::new(),
121+
offset: 0,
122+
size: 0,
123+
}
124+
}
125+
/// Create `ReturnData` from give buffer and slice.
126+
pub fn new(mem: Vec<u8>, offset: usize, size: usize) -> Self {
127+
ReturnData {
128+
mem: mem,
129+
offset: offset,
130+
size: size,
131+
}
132+
}
133+
}
134+
100135
/// Gas Left: either it is a known value, or it needs to be computed by processing
101136
/// a return instruction.
102-
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
103-
pub enum GasLeft<'a> {
137+
#[derive(Debug)]
138+
pub enum GasLeft {
104139
/// Known gas left
105140
Known(U256),
106141
/// Return or Revert instruction must be processed.
107142
NeedsReturn {
108143
/// Amount of gas left.
109144
gas_left: U256,
110145
/// Return data buffer.
111-
data: &'a [u8],
146+
data: ReturnData,
112147
/// Apply or revert state changes on revert.
113148
apply_state: bool
114149
},
@@ -122,6 +157,8 @@ pub struct FinalizationResult {
122157
pub gas_left: U256,
123158
/// Apply execution state changes or revert them.
124159
pub apply_state: bool,
160+
/// Return data buffer.
161+
pub return_data: ReturnData,
125162
}
126163

127164
/// Types that can be "finalized" using an EVM.
@@ -133,13 +170,14 @@ pub trait Finalize {
133170
fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult>;
134171
}
135172

136-
impl<'a> Finalize for Result<GasLeft<'a>> {
173+
impl Finalize for Result<GasLeft> {
137174
fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult> {
138175
match self {
139-
Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true }),
140-
Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, data).map(|gas_left| FinalizationResult {
176+
Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true, return_data: ReturnData::empty() }),
177+
Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, &data).map(|gas_left| FinalizationResult {
141178
gas_left: gas_left,
142179
apply_state: apply_state,
180+
return_data: data,
143181
}),
144182
Err(err) => Err(err),
145183
}

ethcore/src/evm/ext.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//! Interface for Evm externalities.
1818
1919
use util::*;
20-
use evm::{self, Schedule};
20+
use evm::{self, Schedule, ReturnData};
2121
use env_info::*;
2222
use types::executed::CallType;
2323

@@ -34,8 +34,8 @@ pub enum ContractCreateResult {
3434
/// Result of externalities call function.
3535
pub enum MessageCallResult {
3636
/// Returned when message call was successfull.
37-
/// Contains gas left.
38-
Success(U256),
37+
/// Contains gas left and output data.
38+
Success(U256, ReturnData),
3939
/// Returned when message call failed.
4040
/// VM doesn't have to know the reason.
4141
Failed
@@ -109,7 +109,7 @@ pub trait Ext {
109109

110110
/// Should be called when transaction calls `RETURN` opcode.
111111
/// Returns gas_left if cost of returning the data is not too high.
112-
fn ret(self, gas: &U256, data: &[u8]) -> evm::Result<U256> where Self: Sized;
112+
fn ret(self, gas: &U256, data: &ReturnData) -> evm::Result<U256>;
113113

114114
/// Should be called when contract commits suicide.
115115
/// Address to which funds should be refunded.

ethcore/src/evm/instructions.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ lazy_static! {
171171
arr[ADDMOD as usize] = InstructionInfo::new("ADDMOD", 0, 3, 1, false, GasPriceTier::Mid);
172172
arr[MULMOD as usize] = InstructionInfo::new("MULMOD", 0, 3, 1, false, GasPriceTier::Mid);
173173
arr[SIGNEXTEND as usize] = InstructionInfo::new("SIGNEXTEND", 0, 2, 1, false, GasPriceTier::Low);
174+
arr[RETURNDATASIZE as usize] = InstructionInfo::new("RETURNDATASIZE", 0, 0, 1, false, GasPriceTier::Base);
175+
arr[RETURNDATACOPY as usize] = InstructionInfo::new("RETURNDATACOPY", 0, 3, 0, true, GasPriceTier::VeryLow);
174176
arr[SHA3 as usize] = InstructionInfo::new("SHA3", 0, 2, 1, false, GasPriceTier::Special);
175177
arr[ADDRESS as usize] = InstructionInfo::new("ADDRESS", 0, 0, 1, false, GasPriceTier::Base);
176178
arr[BALANCE as usize] = InstructionInfo::new("BALANCE", 0, 1, 1, false, GasPriceTier::Special);
@@ -362,6 +364,10 @@ pub const GASPRICE: Instruction = 0x3a;
362364
pub const EXTCODESIZE: Instruction = 0x3b;
363365
/// copy external code (from another contract)
364366
pub const EXTCODECOPY: Instruction = 0x3c;
367+
/// get the size of the return data buffer for the last call
368+
pub const RETURNDATASIZE: Instruction = 0x3d;
369+
/// copy return data buffer to memory
370+
pub const RETURNDATACOPY: Instruction = 0x3e;
365371

366372
/// get hash of most recent complete block
367373
pub const BLOCKHASH: Instruction = 0x40;

ethcore/src/evm/interpreter/gasometer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ impl<Gas: CostType> Gasometer<Gas> {
173173
let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words);
174174
Request::GasMem(gas, mem_needed(stack.peek(0), stack.peek(1))?)
175175
},
176-
instructions::CALLDATACOPY | instructions::CODECOPY => {
176+
instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => {
177177
Request::GasMemCopy(default_gas, mem_needed(stack.peek(0), stack.peek(2))?, Gas::from_u256(*stack.peek(2))?)
178178
},
179179
instructions::EXTCODECOPY => {

ethcore/src/evm/interpreter/memory.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
1616

1717
use util::U256;
18+
use evm::ReturnData;
1819

1920
pub trait Memory {
2021
/// Retrieve current size of the memory
@@ -36,6 +37,8 @@ pub trait Memory {
3637
/// Retrieve writeable part of memory
3738
fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut[u8];
3839
fn dump(&self);
40+
/// Convert memory into return data.
41+
fn into_return_data(self, offset: usize, size: usize) -> ReturnData;
3942
}
4043

4144
/// Checks whether offset and size is valid memory range
@@ -109,6 +112,10 @@ impl Memory for Vec<u8> {
109112
Memory::resize(self, size)
110113
}
111114
}
115+
116+
fn into_return_data(self, offset: usize, size: usize) -> ReturnData {
117+
ReturnData::new(self, offset, size)
118+
}
112119
}
113120

114121
#[cfg(test)]
@@ -164,4 +171,4 @@ mod tests {
164171
assert_eq!(mem.read_slice(U256::from(0), U256::from(7)), "a67890g".as_bytes());
165172
}
166173
}
167-
}
174+
}

ethcore/src/evm/interpreter/mod.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use std::marker::PhantomData;
3232
use action_params::{ActionParams, ActionValue};
3333
use types::executed::CallType;
3434
use evm::instructions::{self, Instruction, InstructionInfo};
35-
use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType, CreateContractAddress};
35+
use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType, CreateContractAddress, ReturnData};
3636
use bit_set::BitSet;
3737

3838
use util::*;
@@ -102,6 +102,7 @@ enum InstructionResult<Gas> {
102102
pub struct Interpreter<Cost: CostType> {
103103
mem: Vec<u8>,
104104
cache: Arc<SharedCache>,
105+
return_data: ReturnData,
105106
_type: PhantomData<Cost>,
106107
}
107108

@@ -166,9 +167,10 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
166167
},
167168
InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => {
168169
informant.done();
170+
let mem = mem::replace(&mut self.mem, Vec::new());
169171
return Ok(GasLeft::NeedsReturn {
170172
gas_left: gas.as_u256(),
171-
data: self.mem.read_slice(init_off, init_size),
173+
data: mem.into_return_data(usize::from_u256(init_off)?, usize::from_u256(init_size)?),
172174
apply_state: apply
173175
});
174176
},
@@ -187,6 +189,7 @@ impl<Cost: CostType> Interpreter<Cost> {
187189
Interpreter {
188190
mem: Vec::new(),
189191
cache: cache,
192+
return_data: ReturnData::empty(),
190193
_type: PhantomData::default(),
191194
}
192195
}
@@ -233,7 +236,7 @@ impl<Cost: CostType> Interpreter<Cost> {
233236
match instruction {
234237
instructions::MSTORE | instructions::MLOAD => Some((stack.peek(0).low_u64() as usize, 32)),
235238
instructions::MSTORE8 => Some((stack.peek(0).low_u64() as usize, 1)),
236-
instructions::CALLDATACOPY | instructions::CODECOPY => Some((stack.peek(0).low_u64() as usize, stack.peek(2).low_u64() as usize)),
239+
instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => Some((stack.peek(0).low_u64() as usize, stack.peek(2).low_u64() as usize)),
237240
instructions::EXTCODECOPY => Some((stack.peek(1).low_u64() as usize, stack.peek(3).low_u64() as usize)),
238241
instructions::CALL | instructions::CALLCODE => Some((stack.peek(5).low_u64() as usize, stack.peek(6).low_u64() as usize)),
239242
instructions::DELEGATECALL => Some((stack.peek(4).low_u64() as usize, stack.peek(5).low_u64() as usize)),
@@ -362,8 +365,9 @@ impl<Cost: CostType> Interpreter<Cost> {
362365
};
363366

364367
return match call_result {
365-
MessageCallResult::Success(gas_left) => {
368+
MessageCallResult::Success(gas_left, data) => {
366369
stack.push(U256::one());
370+
self.return_data = data;
367371
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater then current one")))
368372
},
369373
MessageCallResult::Failed => {
@@ -501,15 +505,18 @@ impl<Cost: CostType> Interpreter<Cost> {
501505
stack.push(U256::from(len));
502506
},
503507
instructions::CALLDATACOPY => {
504-
self.copy_data_to_memory(stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
508+
Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
509+
},
510+
instructions::RETURNDATACOPY => {
511+
Self::copy_data_to_memory(&mut self.mem, stack, &*self.return_data);
505512
},
506513
instructions::CODECOPY => {
507-
self.copy_data_to_memory(stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8]));
514+
Self::copy_data_to_memory(&mut self.mem, stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8]));
508515
},
509516
instructions::EXTCODECOPY => {
510517
let address = u256_to_address(&stack.pop_back());
511518
let code = ext.extcode(&address)?;
512-
self.copy_data_to_memory(stack, &code);
519+
Self::copy_data_to_memory(&mut self.mem, stack, &code);
513520
},
514521
instructions::GASPRICE => {
515522
stack.push(params.gas_price.clone());
@@ -541,7 +548,7 @@ impl<Cost: CostType> Interpreter<Cost> {
541548
Ok(InstructionResult::Ok)
542549
}
543550

544-
fn copy_data_to_memory(&mut self, stack: &mut Stack<U256>, source: &[u8]) {
551+
fn copy_data_to_memory(mem: &mut Vec<u8>, stack: &mut Stack<U256>, source: &[u8]) {
545552
let dest_offset = stack.pop_back();
546553
let source_offset = stack.pop_back();
547554
let size = stack.pop_back();
@@ -550,9 +557,9 @@ impl<Cost: CostType> Interpreter<Cost> {
550557
let output_end = match source_offset > source_size || size > source_size || source_offset + size > source_size {
551558
true => {
552559
let zero_slice = if source_offset > source_size {
553-
self.mem.writeable_slice(dest_offset, size)
560+
mem.writeable_slice(dest_offset, size)
554561
} else {
555-
self.mem.writeable_slice(dest_offset + source_size - source_offset, source_offset + size - source_size)
562+
mem.writeable_slice(dest_offset + source_size - source_offset, source_offset + size - source_size)
556563
};
557564
for i in zero_slice.iter_mut() {
558565
*i = 0;
@@ -564,7 +571,7 @@ impl<Cost: CostType> Interpreter<Cost> {
564571

565572
if source_offset < source_size {
566573
let output_begin = source_offset.low_u64() as usize;
567-
self.mem.write_slice(dest_offset, &source[output_begin..output_end]);
574+
mem.write_slice(dest_offset, &source[output_begin..output_end]);
568575
}
569576
}
570577

ethcore/src/evm/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ mod tests;
3131
#[cfg(all(feature="benches", test))]
3232
mod benches;
3333

34-
pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType};
34+
pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType, ReturnData};
3535
pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
3636
pub use self::factory::{Factory, VMType};
3737
pub use self::schedule::Schedule;

ethcore/src/evm/tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use util::*;
1818
use action_params::{ActionParams, ActionValue};
1919
use env_info::EnvInfo;
2020
use types::executed::CallType;
21-
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress};
21+
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData};
2222
use std::fmt::Debug;
2323
use tests::helpers::*;
2424
use types::transaction::SYSTEM_ADDRESS;
@@ -149,7 +149,7 @@ impl Ext for FakeExt {
149149
data: data.to_vec(),
150150
code_address: Some(code_address.clone())
151151
});
152-
MessageCallResult::Success(*gas)
152+
MessageCallResult::Success(*gas, ReturnData::empty())
153153
}
154154

155155
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> {
@@ -167,7 +167,7 @@ impl Ext for FakeExt {
167167
});
168168
}
169169

170-
fn ret(self, _gas: &U256, _data: &[u8]) -> evm::Result<U256> {
170+
fn ret(self, _gas: &U256, _data: &ReturnData) -> evm::Result<U256> {
171171
unimplemented!();
172172
}
173173

0 commit comments

Comments
 (0)