@@ -25,9 +25,106 @@ export type ObserveTraceTests<M extends { [name: string]: any }> = {
2525 * for additional unexpected values in between and around the expected values.
2626 */
2727export const observeTraceTests : ObserveTraceTests < {
28- "storage string" : string ;
28+ "string storage" : string ;
29+ "uint256[] memory" : number [ ] ;
2930} > = {
30- "storage string" : {
31+ "uint256[] memory" : {
32+ pointer : findExamplePointer ( "uint256-array-memory-pointer-slot" ) ,
33+ compileOptions : prepareCompileOptions ( {
34+ path : "Uint256Arraymemory.sol" ,
35+ contractName : "Uint256ArrayMemory" ,
36+ content : `contract Uint256ArrayMemory {
37+ constructor() {
38+ uint256[] memory values = new uint256[](0);
39+ values = appendToArray(values, 1);
40+ values = appendToArray(values, 2);
41+ values = appendToArray(values, 3);
42+ }
43+
44+ function appendToArray(
45+ uint256[] memory arr,
46+ uint256 value
47+ )
48+ private
49+ pure
50+ returns (uint256[] memory)
51+ {
52+ uint256[] memory newArray = new uint256[](arr.length + 1);
53+
54+ for (uint i = 0; i < arr.length; i++) {
55+ newArray[i] = arr[i];
56+ }
57+
58+ newArray[arr.length] = value;
59+ return newArray;
60+ }
61+ }
62+ `
63+ } ) ,
64+
65+ expectedValues : [
66+ [ ] ,
67+ [ 1 ] ,
68+ [ 1 , 2 ] ,
69+ [ 1 , 2 , 3 ]
70+ ] ,
71+
72+ async observe ( { regions, read } , state ) : Promise < number [ ] > {
73+ const items = regions . named ( "array-item" ) ;
74+
75+ return ( await Promise . all (
76+ items . map ( async ( item ) => {
77+ const data = await read ( item ) ;
78+
79+ return Number ( data . asUint ( ) ) ;
80+ } )
81+ ) ) ;
82+ } ,
83+
84+ equals ( a , b ) {
85+ if ( a . length !== b . length ) {
86+ return false ;
87+ }
88+
89+ for ( const [ index , value ] of a . entries ( ) ) {
90+ if ( b [ index ] !== value ) {
91+ return false ;
92+ }
93+ }
94+
95+ return true ;
96+ } ,
97+
98+ // this function uses observation of solc + viaIR behavior to determine
99+ // that the memory array we're looking for is going to have a pointer at
100+ // the bottom of the stack
101+ //
102+ // also include a check to exclude observation when that bottom stack value
103+ // would have `cursor.view` produce a ton of regions.
104+ async shouldObserve ( state ) {
105+ const stackLength = await state . stack . length ;
106+ if ( stackLength === 0n ) {
107+ return false ;
108+ }
109+
110+ // only consider the bottom of the stack
111+ const arrayOffset = await state . stack . peek ( { depth : stackLength - 1n } ) ;
112+
113+ const arrayCount = await state . memory . read ( {
114+ slice : {
115+ offset : arrayOffset . asUint ( ) ,
116+ length : 32n
117+ }
118+ } )
119+
120+ // return false;
121+ const isObservable = arrayCount . asUint ( ) < 4n ;
122+ if ( isObservable ) {
123+ }
124+ return isObservable ;
125+ }
126+ } ,
127+ "string storage" : {
31128 pointer : findExamplePointer ( "string-storage-contract-variable-slot" ) ,
32129
33130 compileOptions : prepareCompileOptions ( {
0 commit comments