Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.

Commit b900b84

Browse files
[feat] returndatacopy implemented (#506)
* init impl of returndatacopy * add aux_bytes to CopyEvent * add read_steps and write_steps and rlc_acc_read and rlc_acc_write * add assert * using real dst word value * rlc_acc_read/write only counts when not padding * fix overflow * fix typo * add read_word * fix rwc * write after read one by one * add test * fix constraint * fix typo * update test * fix lookup * fix rw_increase * update return gadget * fix root create in return tests * fix returndatacopy, add calldatacopy non root * fix trace test with last_callee_memory * fix calldatacopy non root * update create pass for non persistent etc. * fix calldatacopy test * add constrain rlc_acc_read == rlc_acc_write * cargo fmt --------- Co-authored-by: Dream Wu <wwuwwei@126.com>
1 parent b881f21 commit b900b84

File tree

18 files changed

+781
-263
lines changed

18 files changed

+781
-263
lines changed

bus-mapping/src/circuit_input_builder/call.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ pub struct Call {
5757
pub call_id: usize,
5858
/// Caller's id.
5959
pub caller_id: usize,
60-
/// Last Callee's id.
61-
pub last_callee_id: usize,
6260
/// Type of call
6361
pub kind: CallKind,
6462
/// This call is being executed without write access (STATIC)
@@ -91,10 +89,14 @@ pub struct Call {
9189
pub return_data_offset: u64,
9290
/// Return data length
9391
pub return_data_length: u64,
92+
/// Last Callee's id.
93+
pub last_callee_id: usize,
9494
/// last callee's return data offset
9595
pub last_callee_return_data_offset: u64,
9696
/// last callee's return data length
9797
pub last_callee_return_data_length: u64,
98+
/// last callee's memory
99+
pub last_callee_memory: Memory,
98100
}
99101

100102
impl Call {

bus-mapping/src/circuit_input_builder/execution.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,8 @@ pub struct CopyEvent {
243243
pub rw_counter_start: RWCounter,
244244
/// Represents the list of (bytes, is_code, mask) copied during this copy event
245245
pub bytes: Vec<(u8, bool, bool)>,
246-
// todo: add aux_bytes here
246+
/// Represents the list of (bytes, is_code, mask) read to copy during this copy event
247+
pub aux_bytes: Option<Vec<(u8, bool, bool)>>,
247248
}
248249

249250
impl CopyEvent {
@@ -293,6 +294,12 @@ impl CopyEvent {
293294

294295
// increase in rw counter from the start of the copy event to step index
295296
fn rw_counter_increase(&self, step_index: usize) -> u64 {
297+
match (self.src_type, self.dst_type) {
298+
(CopyDataType::Memory, CopyDataType::Memory) => {
299+
return step_index as u64 % 2 + 2 * (step_index as f32 / 64.0).floor() as u64;
300+
}
301+
_ => {}
302+
}
296303
let source_rw_increase = match self.src_type {
297304
CopyDataType::Bytecode | CopyDataType::TxCalldata => 0,
298305
CopyDataType::Memory => (step_index as u64 / 2) / 32,

bus-mapping/src/circuit_input_builder/input_state_ref.rs

Lines changed: 283 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ use ethers_core::{
2828
k256::{elliptic_curve::consts::U4, sha2::digest::typenum::Minimum},
2929
utils::{get_contract_address, get_create2_address, keccak256},
3030
};
31-
use std::{cmp::max, io::copy, mem};
31+
use std::{
32+
cmp::{max, min},
33+
io::copy,
34+
mem,
35+
};
3236

3337
/// Reference to the internal state of the CircuitInputBuilder in a particular
3438
/// [`ExecStep`].
@@ -915,6 +919,7 @@ impl<'a> CircuitInputStateRef<'a> {
915919
return_data_length,
916920
last_callee_return_data_offset: 0,
917921
last_callee_return_data_length: 0,
922+
last_callee_memory: Memory::default(),
918923
};
919924

920925
Ok(call)
@@ -1036,6 +1041,7 @@ impl<'a> CircuitInputStateRef<'a> {
10361041
/// previous call context.
10371042
pub fn handle_return(&mut self, step: &GethExecStep) -> Result<(), Error> {
10381043
// handle return_data
1044+
let callee_memory = self.call_ctx()?.memory.clone();
10391045
let (return_data_offset, return_data_length) = {
10401046
if !self.call()?.is_root {
10411047
let (offset, length) = match step.op {
@@ -1051,7 +1057,6 @@ impl<'a> CircuitInputStateRef<'a> {
10511057
)
10521058
};
10531059
// At the moment it conflicts with `call_ctx` and `caller_ctx`.
1054-
let callee_memory = self.call_ctx()?.memory.clone();
10551060
let caller_ctx = self.caller_ctx_mut()?;
10561061
caller_ctx.return_data.resize(length, 0);
10571062
if length != 0 {
@@ -1130,6 +1135,7 @@ impl<'a> CircuitInputStateRef<'a> {
11301135
caller.last_callee_return_data_length = return_data_length;
11311136
caller.last_callee_return_data_offset = return_data_offset;
11321137
}
1138+
caller.last_callee_memory = callee_memory;
11331139
}
11341140

11351141
// If current call has caller_ctx (has caller)
@@ -1679,7 +1685,7 @@ impl<'a> CircuitInputStateRef<'a> {
16791685
}
16801686

16811687
/// Generate copy steps for call data.
1682-
pub(crate) fn gen_copy_steps_for_call_data(
1688+
pub(crate) fn gen_copy_steps_for_call_data_root(
16831689
&mut self,
16841690
exec_step: &mut ExecStep,
16851691
src_addr: u64,
@@ -1745,6 +1751,257 @@ impl<'a> CircuitInputStateRef<'a> {
17451751
Ok(copy_steps)
17461752
}
17471753

1754+
pub(crate) fn gen_copy_steps_for_call_data_non_root(
1755+
&mut self,
1756+
exec_step: &mut ExecStep,
1757+
src_addr: u64,
1758+
src_addr_end: u64,
1759+
dst_addr: u64, // memory dest starting addr
1760+
copy_length: u64, // number of bytes to copy, with padding
1761+
) -> Result<(Vec<(u8, bool, bool)>, Vec<(u8, bool, bool)>), Error> {
1762+
let mut read_steps = Vec::with_capacity(copy_length as usize);
1763+
let mut write_steps = Vec::with_capacity(copy_length as usize);
1764+
1765+
if copy_length == 0 {
1766+
return Ok((read_steps, write_steps));
1767+
}
1768+
1769+
let caller_id = self.call()?.caller_id;
1770+
let current_call_id = self.call()?.call_id;
1771+
1772+
let (_, src_begin_slot) = self.get_addr_shift_slot(src_addr).unwrap();
1773+
let (_, src_end_slot) = self.get_addr_shift_slot(src_addr_end).unwrap();
1774+
let (_, dst_begin_slot) = self.get_addr_shift_slot(dst_addr).unwrap();
1775+
let (_, dst_end_slot) = self.get_addr_shift_slot(dst_addr + copy_length).unwrap();
1776+
1777+
println!("overflow check: {} {}", src_begin_slot, src_end_slot);
1778+
println!("overflow check: {} {}", dst_begin_slot, dst_end_slot);
1779+
let slot_count = max(
1780+
(src_end_slot - src_begin_slot),
1781+
(dst_end_slot - dst_begin_slot),
1782+
) as usize;
1783+
let src_end_slot = src_begin_slot as usize + slot_count;
1784+
let dst_end_slot = dst_begin_slot as usize + slot_count;
1785+
1786+
let mut caller_memory = self.caller_ctx()?.memory.clone();
1787+
caller_memory.extend_at_least(src_end_slot as usize + 32);
1788+
let mut call_memory = self.call_ctx()?.memory.clone();
1789+
call_memory.extend_at_least(dst_end_slot as usize + 32);
1790+
let read_slot_bytes =
1791+
caller_memory.0[src_begin_slot as usize..(src_end_slot + 32) as usize].to_vec();
1792+
let write_slot_bytes =
1793+
call_memory.0[dst_begin_slot as usize..(dst_end_slot + 32) as usize].to_vec();
1794+
1795+
Self::gen_memory_copy_steps(
1796+
&mut read_steps,
1797+
&caller_memory.0,
1798+
slot_count + 32,
1799+
src_addr as usize,
1800+
src_begin_slot as usize,
1801+
copy_length as usize,
1802+
);
1803+
1804+
Self::gen_memory_copy_steps(
1805+
&mut write_steps,
1806+
&call_memory.0,
1807+
slot_count + 32,
1808+
dst_addr as usize,
1809+
dst_begin_slot as usize,
1810+
copy_length as usize,
1811+
);
1812+
1813+
let mut copy_rwc_inc = 0;
1814+
let mut src_chunk_index = src_begin_slot;
1815+
let mut dst_chunk_index = dst_begin_slot;
1816+
// memory word reads from source and writes to destination word
1817+
for (read_chunk, write_chunk) in read_slot_bytes.chunks(32).zip(write_slot_bytes.chunks(32))
1818+
{
1819+
self.push_op(
1820+
exec_step,
1821+
RW::READ,
1822+
MemoryWordOp::new(
1823+
caller_id,
1824+
src_chunk_index.into(),
1825+
Word::from_big_endian(read_chunk),
1826+
),
1827+
);
1828+
println!(
1829+
"read chunk: {} {} {:?}",
1830+
caller_id, src_chunk_index, read_chunk
1831+
);
1832+
src_chunk_index = src_chunk_index + 32;
1833+
1834+
self.push_op(
1835+
exec_step,
1836+
RW::WRITE,
1837+
MemoryWordOp::new(
1838+
current_call_id,
1839+
dst_chunk_index.into(),
1840+
Word::from_big_endian(write_chunk),
1841+
),
1842+
);
1843+
println!(
1844+
"write chunk: {} {} {:?}",
1845+
current_call_id, dst_chunk_index, write_chunk
1846+
);
1847+
dst_chunk_index = dst_chunk_index + 32;
1848+
1849+
copy_rwc_inc = copy_rwc_inc + 2;
1850+
}
1851+
1852+
println!(
1853+
r#"busmapping:
1854+
src_addr = {src_addr}
1855+
dst_addr = {dst_addr}
1856+
copy_length = {copy_length}
1857+
1858+
src_end = {src_addr_end}
1859+
dst_end = {}
1860+
1861+
src_begin_slot = {src_begin_slot}
1862+
src_end_slot = {src_end_slot}
1863+
dst_begin_slot = {dst_begin_slot}
1864+
dst_end_slot = {dst_end_slot}
1865+
slot_count = {slot_count}
1866+
1867+
len(read_slot_bytes) = {}
1868+
len(write_slot_bytes) = {}
1869+
1870+
copy_rwc_inc = {copy_rwc_inc}"#,
1871+
dst_addr + copy_length,
1872+
read_slot_bytes.len(),
1873+
write_slot_bytes.len()
1874+
);
1875+
1876+
Ok((read_steps, write_steps))
1877+
}
1878+
1879+
pub(crate) fn gen_copy_steps_for_return_data(
1880+
&mut self,
1881+
exec_step: &mut ExecStep,
1882+
src_addr: u64,
1883+
src_addr_end: u64,
1884+
dst_addr: u64, // memory dest starting addr
1885+
copy_length: u64, // number of bytes to copy, with padding
1886+
) -> Result<(Vec<(u8, bool, bool)>, Vec<(u8, bool, bool)>), Error> {
1887+
let mut read_steps = Vec::with_capacity(copy_length as usize);
1888+
let mut write_steps = Vec::with_capacity(copy_length as usize);
1889+
1890+
if copy_length == 0 {
1891+
return Ok((read_steps, write_steps));
1892+
}
1893+
1894+
let last_callee_id = self.call()?.last_callee_id;
1895+
let current_call_id = self.call()?.call_id;
1896+
1897+
let (_, src_begin_slot) = self.get_addr_shift_slot(src_addr).unwrap();
1898+
let (_, src_end_slot) = self.get_addr_shift_slot(src_addr + copy_length).unwrap();
1899+
// won't be copy out of bound, it should be handle by geth error ReturnDataOutOfBounds
1900+
assert!(src_addr + copy_length <= src_addr_end);
1901+
let (_, dst_begin_slot) = self.get_addr_shift_slot(dst_addr).unwrap();
1902+
let (_, dst_end_slot) = self.get_addr_shift_slot(dst_addr + copy_length).unwrap();
1903+
1904+
let slot_count = max(
1905+
(src_end_slot - src_begin_slot),
1906+
(dst_end_slot - dst_begin_slot),
1907+
) as usize;
1908+
let src_end_slot = src_begin_slot as usize + slot_count;
1909+
let dst_end_slot = dst_begin_slot as usize + slot_count;
1910+
1911+
let mut last_callee_memory = self.call()?.last_callee_memory.clone();
1912+
last_callee_memory.extend_at_least(src_end_slot as usize + 32);
1913+
let mut call_memory = self.call_ctx()?.memory.clone();
1914+
call_memory.extend_at_least(dst_end_slot as usize + 32);
1915+
let read_slot_bytes =
1916+
last_callee_memory.0[src_begin_slot as usize..(src_end_slot + 32) as usize].to_vec();
1917+
let write_slot_bytes =
1918+
call_memory.0[dst_begin_slot as usize..(dst_end_slot + 32) as usize].to_vec();
1919+
debug_assert_eq!(write_slot_bytes.len(), slot_count + 32);
1920+
1921+
Self::gen_memory_copy_steps(
1922+
&mut read_steps,
1923+
&last_callee_memory.0,
1924+
slot_count + 32,
1925+
src_addr as usize,
1926+
src_begin_slot as usize,
1927+
copy_length as usize,
1928+
);
1929+
1930+
Self::gen_memory_copy_steps(
1931+
&mut write_steps,
1932+
&call_memory.0,
1933+
slot_count + 32,
1934+
dst_addr as usize,
1935+
dst_begin_slot as usize,
1936+
copy_length as usize,
1937+
);
1938+
1939+
let mut copy_rwc_inc = 0;
1940+
let mut src_chunk_index = src_begin_slot;
1941+
let mut dst_chunk_index = dst_begin_slot;
1942+
// memory word reads from source and writes to destination word
1943+
for (read_chunk, write_chunk) in read_slot_bytes.chunks(32).zip(write_slot_bytes.chunks(32))
1944+
{
1945+
self.push_op(
1946+
exec_step,
1947+
RW::READ,
1948+
MemoryWordOp::new(
1949+
last_callee_id,
1950+
src_chunk_index.into(),
1951+
Word::from_big_endian(read_chunk),
1952+
),
1953+
);
1954+
println!(
1955+
"read chunk: {} {} {:?}",
1956+
last_callee_id, src_chunk_index, read_chunk
1957+
);
1958+
src_chunk_index = src_chunk_index + 32;
1959+
1960+
self.push_op(
1961+
exec_step,
1962+
RW::WRITE,
1963+
MemoryWordOp::new(
1964+
current_call_id,
1965+
dst_chunk_index.into(),
1966+
Word::from_big_endian(write_chunk),
1967+
),
1968+
);
1969+
println!(
1970+
"write chunk: {} {} {:?}",
1971+
current_call_id, dst_chunk_index, write_chunk
1972+
);
1973+
dst_chunk_index = dst_chunk_index + 32;
1974+
1975+
copy_rwc_inc = copy_rwc_inc + 2;
1976+
}
1977+
1978+
println!(
1979+
r#"busmapping:
1980+
src_addr = {src_addr}
1981+
dst_addr = {dst_addr}
1982+
copy_length = {copy_length}
1983+
1984+
src_end = {src_addr_end}
1985+
dst_end = {}
1986+
1987+
src_begin_slot = {src_begin_slot}
1988+
src_end_slot = {src_end_slot}
1989+
dst_begin_slot = {dst_begin_slot}
1990+
dst_end_slot = {dst_end_slot}
1991+
slot_count = {slot_count}
1992+
1993+
len(read_slot_bytes) = {}
1994+
len(write_slot_bytes) = {}
1995+
1996+
copy_rwc_inc = {copy_rwc_inc}"#,
1997+
dst_addr + copy_length,
1998+
read_slot_bytes.len(),
1999+
write_slot_bytes.len()
2000+
);
2001+
2002+
Ok((read_steps, write_steps))
2003+
}
2004+
17482005
pub(crate) fn gen_copy_steps_for_log(
17492006
&mut self,
17502007
exec_step: &mut ExecStep,
@@ -1808,4 +2065,27 @@ impl<'a> CircuitInputStateRef<'a> {
18082065
}
18092066

18102067
// TODO: add new gen_copy_steps for common use
2068+
pub(crate) fn gen_memory_copy_steps(
2069+
steps: &mut Vec<(u8, bool, bool)>,
2070+
memory: &[u8],
2071+
slot_bytes_len: usize,
2072+
offset_addr: usize,
2073+
begin_slot: usize,
2074+
length: usize,
2075+
) {
2076+
for idx in 0..slot_bytes_len {
2077+
let value = memory[begin_slot as usize + idx];
2078+
// padding unaligned copy of 32 bytes
2079+
if idx + begin_slot < offset_addr {
2080+
// front mask byte
2081+
steps.push((value, false, true));
2082+
} else if idx + begin_slot >= offset_addr + length {
2083+
// back mask byte
2084+
steps.push((value, false, true));
2085+
} else {
2086+
// real copy byte
2087+
steps.push((value, false, false));
2088+
}
2089+
}
2090+
}
18112091
}

0 commit comments

Comments
 (0)