@@ -2,6 +2,196 @@ pub extern crate evmc_sys;
22pub use evmc_sys as ffi;
33
44// TODO: Add helpers for host interface
5- // TODO: Add convenient helpers for evmc_result
65// TODO: Add convenient helpers for evmc_execute
76// TODO: Add a derive macro here for creating evmc_create
7+
8+ /// EVMC result structure.
9+ pub struct ExecutionResult {
10+ status_code : ffi:: evmc_status_code ,
11+ gas_left : i64 ,
12+ output : Option < Vec < u8 > > ,
13+ create_address : ffi:: evmc_address ,
14+ }
15+
16+ impl ExecutionResult {
17+ pub fn new (
18+ _status_code : ffi:: evmc_status_code ,
19+ _gas_left : i64 ,
20+ _output : Option < Vec < u8 > > ,
21+ _create_address : ffi:: evmc_address ,
22+ ) -> Self {
23+ ExecutionResult {
24+ status_code : _status_code,
25+ gas_left : _gas_left,
26+ output : _output,
27+ create_address : _create_address,
28+ }
29+ }
30+
31+ pub fn get_status_code ( & self ) -> ffi:: evmc_status_code {
32+ self . status_code
33+ }
34+
35+ pub fn get_gas_left ( & self ) -> i64 {
36+ self . gas_left
37+ }
38+
39+ pub fn get_output ( & self ) -> Option < & Vec < u8 > > {
40+ self . output . as_ref ( )
41+ }
42+
43+ pub fn get_create_address ( & self ) -> Option < & ffi:: evmc_address > {
44+ // Only return Some if the address is valid (e.g. the status is EVMC_SUCCESS)
45+ if self . status_code == ffi:: evmc_status_code:: EVMC_SUCCESS {
46+ Some ( & self . create_address )
47+ } else {
48+ None
49+ }
50+ }
51+ }
52+
53+ impl From < ffi:: evmc_result > for ExecutionResult {
54+ fn from ( result : ffi:: evmc_result ) -> Self {
55+ let ret = ExecutionResult {
56+ status_code : result. status_code ,
57+ gas_left : result. gas_left ,
58+ output : if !result. output_data . is_null ( ) {
59+ // Pre-allocate a vector.
60+ let mut buf: Vec < u8 > = Vec :: with_capacity ( result. output_size ) ;
61+
62+ unsafe {
63+ // Set the len of the vec manually.
64+ buf. set_len ( result. output_size ) ;
65+ // Copy from the C struct's buffer to the vec's buffer.
66+ std:: ptr:: copy ( result. output_data , buf. as_mut_ptr ( ) , result. output_size ) ;
67+ }
68+
69+ Some ( buf)
70+ } else {
71+ None
72+ } ,
73+ create_address : result. create_address ,
74+ } ;
75+
76+ // Release allocated ffi struct.
77+ if result. release . is_some ( ) {
78+ unsafe {
79+ result. release . unwrap ( ) ( & result as * const ffi:: evmc_result ) ;
80+ }
81+ }
82+
83+ ret
84+ }
85+ }
86+
87+ /// Returns a pointer to a heap-allocated evmc_result.
88+ impl Into < * const ffi:: evmc_result > for ExecutionResult {
89+ fn into ( self ) -> * const ffi:: evmc_result {
90+ let ( buffer, len) = if let Some ( buf) = self . output {
91+ let buf_len = buf. len ( ) ;
92+
93+ // Manually allocate heap memory for the new home of the output buffer.
94+ let memlayout = std:: alloc:: Layout :: from_size_align ( buf_len, 1 ) . expect ( "Bad layout" ) ;
95+ let new_buf = unsafe { std:: alloc:: alloc ( memlayout) } ;
96+ unsafe {
97+ // Copy the data into the allocated buffer.
98+ std:: ptr:: copy ( buf. as_ptr ( ) , new_buf, buf_len) ;
99+ }
100+
101+ ( new_buf as * const u8 , buf_len)
102+ } else {
103+ ( std:: ptr:: null ( ) , 0 )
104+ } ;
105+
106+ Box :: into_raw ( Box :: new ( ffi:: evmc_result {
107+ status_code : self . status_code ,
108+ gas_left : self . gas_left ,
109+ output_data : buffer,
110+ output_size : len,
111+ release : Some ( release_result) ,
112+ create_address : self . create_address ,
113+ padding : [ 0u8 ; 4 ] ,
114+ } ) )
115+ }
116+ }
117+
118+ /// Callback to pass across FFI, de-allocating the struct.
119+ extern "C" fn release_result ( result : * const ffi:: evmc_result ) {
120+ unsafe {
121+ let tmp = Box :: from_raw ( result as * mut ffi:: evmc_result ) ;
122+ if tmp. output_data . is_null ( ) {
123+ let buf_layout =
124+ std:: alloc:: Layout :: from_size_align ( tmp. output_size , 1 ) . expect ( "Bad layout" ) ;
125+ std:: alloc:: dealloc ( tmp. output_data as * mut u8 , buf_layout) ;
126+ }
127+ Box :: from_raw ( result as * mut ffi:: evmc_result ) ;
128+ }
129+ }
130+
131+ #[ cfg( test) ]
132+ mod tests {
133+ use super :: * ;
134+ use evmc_sys as ffi;
135+
136+ #[ test]
137+ fn new_result ( ) {
138+ let r = ExecutionResult :: new (
139+ ffi:: evmc_status_code:: EVMC_FAILURE ,
140+ 420 ,
141+ None ,
142+ ffi:: evmc_address { bytes : [ 0u8 ; 20 ] } ,
143+ ) ;
144+
145+ assert ! ( r. get_status_code( ) == ffi:: evmc_status_code:: EVMC_FAILURE ) ;
146+ assert ! ( r. get_gas_left( ) == 420 ) ;
147+ assert ! ( r. get_output( ) . is_none( ) ) ;
148+
149+ // Ensure that an address is not returned if it is not valid, per status code.
150+ assert ! ( r. get_create_address( ) . is_none( ) ) ;
151+ }
152+
153+ #[ test]
154+ fn from_ffi ( ) {
155+ let f = ffi:: evmc_result {
156+ status_code : ffi:: evmc_status_code:: EVMC_SUCCESS ,
157+ gas_left : 1337 ,
158+ output_data : Box :: into_raw ( Box :: new ( [ 0xde , 0xad , 0xbe , 0xef ] ) ) as * const u8 ,
159+ output_size : 4 ,
160+ release : None ,
161+ create_address : ffi:: evmc_address { bytes : [ 0u8 ; 20 ] } ,
162+ padding : [ 0u8 ; 4 ] ,
163+ } ;
164+
165+ let r: ExecutionResult = f. into ( ) ;
166+
167+ assert ! ( r. get_status_code( ) == ffi:: evmc_status_code:: EVMC_SUCCESS ) ;
168+ assert ! ( r. get_gas_left( ) == 1337 ) ;
169+ assert ! ( r. get_output( ) . is_some( ) ) ;
170+ assert ! ( r. get_output( ) . unwrap( ) . len( ) == 4 ) ;
171+ assert ! ( r. get_create_address( ) . is_some( ) ) ;
172+ }
173+
174+ #[ test]
175+ fn into_ffi ( ) {
176+ let r = ExecutionResult :: new (
177+ ffi:: evmc_status_code:: EVMC_FAILURE ,
178+ 420 ,
179+ Some ( vec ! [ 0xc0 , 0xff , 0xee , 0x71 , 0x75 ] ) ,
180+ ffi:: evmc_address { bytes : [ 0u8 ; 20 ] } ,
181+ ) ;
182+
183+ let f: * const ffi:: evmc_result = r. into ( ) ;
184+ assert ! ( !f. is_null( ) ) ;
185+ unsafe {
186+ assert ! ( ( * f) . status_code == ffi:: evmc_status_code:: EVMC_FAILURE ) ;
187+ assert ! ( ( * f) . gas_left == 420 ) ;
188+ assert ! ( !( * f) . output_data. is_null( ) ) ;
189+ assert ! ( ( * f) . output_size == 5 ) ;
190+ assert ! (
191+ std:: slice:: from_raw_parts( ( * f) . output_data, 5 ) as & [ u8 ]
192+ == & [ 0xc0 , 0xff , 0xee , 0x71 , 0x75 ]
193+ ) ;
194+ assert ! ( ( * f) . create_address. bytes == [ 0u8 ; 20 ] ) ;
195+ }
196+ }
197+ }
0 commit comments