@@ -298,11 +298,31 @@ pub mod rpc {
298298 ) ) ;
299299 }
300300 let contract_data_entry = & entries[ 0 ] ;
301- match LedgerEntryData :: from_xdr_base64 ( & contract_data_entry. xdr , Limits :: none ( ) ) ? {
302- LedgerEntryData :: ContractCode ( xdr:: ContractCodeEntry { code, .. } ) => Ok ( code. into ( ) ) ,
303- scval => Err ( Error :: UnexpectedContractCodeDataType ( scval) ) ,
304- }
301+ let code = match LedgerEntryData :: from_xdr_base64 ( & contract_data_entry. xdr , Limits :: none ( ) ) ?
302+ {
303+ LedgerEntryData :: ContractCode ( xdr:: ContractCodeEntry { code, .. } ) => Vec :: from ( code) ,
304+ scval => return Err ( Error :: UnexpectedContractCodeDataType ( scval) ) ,
305+ } ;
306+ super :: verify_wasm_hash ( & code, hash) ?;
307+ Ok ( code)
308+ }
309+ }
310+
311+ // Uses `Error::NotFound` because `soroban_rpc::Error` has no integrity/mismatch
312+ // variant. The message makes the actual failure reason clear.
313+ fn verify_wasm_hash ( code : & [ u8 ] , expected_hash : & Hash ) -> Result < ( ) , soroban_rpc:: Error > {
314+ let computed_hash = Hash ( Sha256 :: digest ( code) . into ( ) ) ;
315+ if computed_hash != * expected_hash {
316+ return Err ( soroban_rpc:: Error :: NotFound (
317+ "WASM hash mismatch" . to_string ( ) ,
318+ format ! (
319+ "expected {}, got {}" ,
320+ hex:: encode( expected_hash. 0 ) ,
321+ hex:: encode( computed_hash. 0 ) ,
322+ ) ,
323+ ) ) ;
305324 }
325+ Ok ( ( ) )
306326}
307327
308328#[ cfg( test) ]
@@ -324,4 +344,36 @@ mod tests {
324344 Err ( err) => panic ! ( "Failed to parse contract id: {err}" ) ,
325345 }
326346 }
347+
348+ #[ test]
349+ fn test_verify_wasm_hash_matching ( ) {
350+ use sha2:: { Digest , Sha256 } ;
351+ use stellar_xdr:: curr:: Hash ;
352+
353+ let wasm_bytes = b"\0 asm fake wasm content" ;
354+ let correct_hash = Hash ( Sha256 :: digest ( wasm_bytes) . into ( ) ) ;
355+ assert ! ( verify_wasm_hash( wasm_bytes, & correct_hash) . is_ok( ) ) ;
356+ }
357+
358+ #[ test]
359+ fn test_verify_wasm_hash_mismatch ( ) {
360+ use stellar_xdr:: curr:: Hash ;
361+
362+ let wasm_bytes = b"\0 asm fake wasm content" ;
363+ let wrong_hash = Hash ( [ 0xAB ; 32 ] ) ;
364+ let err = verify_wasm_hash ( wasm_bytes, & wrong_hash) . unwrap_err ( ) ;
365+ let err_msg = err. to_string ( ) ;
366+ assert ! (
367+ err_msg. contains( "WASM hash mismatch" ) ,
368+ "expected 'WASM hash mismatch' in error: {err_msg}"
369+ ) ;
370+ assert ! (
371+ err_msg. contains( "abababababababababababababababababababababababababababababababab" ) ,
372+ "expected expected-hash in error: {err_msg}"
373+ ) ;
374+ assert ! (
375+ err_msg. contains( "501dc4e05f47c4713c4a27e89a5b07ed769bb2cc858bcf46de9bed13ae65af29" ) ,
376+ "expected computed-hash in error: {err_msg}"
377+ ) ;
378+ }
327379}
0 commit comments