@@ -28,7 +28,11 @@ use ethers_core::{
28
28
k256:: { elliptic_curve:: consts:: U4 , sha2:: digest:: typenum:: Minimum } ,
29
29
utils:: { get_contract_address, get_create2_address, keccak256} ,
30
30
} ;
31
- use std:: { cmp:: max, io:: copy, mem} ;
31
+ use std:: {
32
+ cmp:: { max, min} ,
33
+ io:: copy,
34
+ mem,
35
+ } ;
32
36
33
37
/// Reference to the internal state of the CircuitInputBuilder in a particular
34
38
/// [`ExecStep`].
@@ -915,6 +919,7 @@ impl<'a> CircuitInputStateRef<'a> {
915
919
return_data_length,
916
920
last_callee_return_data_offset : 0 ,
917
921
last_callee_return_data_length : 0 ,
922
+ last_callee_memory : Memory :: default ( ) ,
918
923
} ;
919
924
920
925
Ok ( call)
@@ -1036,6 +1041,7 @@ impl<'a> CircuitInputStateRef<'a> {
1036
1041
/// previous call context.
1037
1042
pub fn handle_return ( & mut self , step : & GethExecStep ) -> Result < ( ) , Error > {
1038
1043
// handle return_data
1044
+ let callee_memory = self . call_ctx ( ) ?. memory . clone ( ) ;
1039
1045
let ( return_data_offset, return_data_length) = {
1040
1046
if !self . call ( ) ?. is_root {
1041
1047
let ( offset, length) = match step. op {
@@ -1051,7 +1057,6 @@ impl<'a> CircuitInputStateRef<'a> {
1051
1057
)
1052
1058
} ;
1053
1059
// At the moment it conflicts with `call_ctx` and `caller_ctx`.
1054
- let callee_memory = self . call_ctx ( ) ?. memory . clone ( ) ;
1055
1060
let caller_ctx = self . caller_ctx_mut ( ) ?;
1056
1061
caller_ctx. return_data . resize ( length, 0 ) ;
1057
1062
if length != 0 {
@@ -1130,6 +1135,7 @@ impl<'a> CircuitInputStateRef<'a> {
1130
1135
caller. last_callee_return_data_length = return_data_length;
1131
1136
caller. last_callee_return_data_offset = return_data_offset;
1132
1137
}
1138
+ caller. last_callee_memory = callee_memory;
1133
1139
}
1134
1140
1135
1141
// If current call has caller_ctx (has caller)
@@ -1679,7 +1685,7 @@ impl<'a> CircuitInputStateRef<'a> {
1679
1685
}
1680
1686
1681
1687
/// 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 (
1683
1689
& mut self ,
1684
1690
exec_step : & mut ExecStep ,
1685
1691
src_addr : u64 ,
@@ -1745,6 +1751,257 @@ impl<'a> CircuitInputStateRef<'a> {
1745
1751
Ok ( copy_steps)
1746
1752
}
1747
1753
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
+
1748
2005
pub ( crate ) fn gen_copy_steps_for_log (
1749
2006
& mut self ,
1750
2007
exec_step : & mut ExecStep ,
@@ -1808,4 +2065,27 @@ impl<'a> CircuitInputStateRef<'a> {
1808
2065
}
1809
2066
1810
2067
// 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
+ }
1811
2091
}
0 commit comments