@@ -256,4 +256,253 @@ mod tests {
256256 assert_eq ! ( data. get( "balance" ) , recovered. get( "balance" ) ) ;
257257 assert_eq ! ( data. get( "active" ) , recovered. get( "active" ) ) ;
258258 }
259+
260+ // -------------------------------------------------------------------------
261+ // ABI cross-validation vectors.
262+ //
263+ // These tests encode known byte sequences by hand and assert that
264+ // graph-node's ToRustWasm/FromRustWasm impls produce identical bytes.
265+ // The same raw bytes are validated against the Graphite SDK in
266+ // graphite/src/abi_vectors_tests.rs.
267+ // -------------------------------------------------------------------------
268+
269+ fn le32 ( n : u32 ) -> [ u8 ; 4 ] {
270+ n. to_le_bytes ( )
271+ }
272+
273+ // -- Null (tag 0x00) --
274+
275+ #[ test]
276+ fn abi_vec_null_encodes_to_single_byte ( ) {
277+ let bytes = Value :: Null . to_bytes ( ) ;
278+ assert_eq ! ( bytes, [ 0x00u8 ] ) ;
279+ }
280+
281+ #[ test]
282+ fn abi_vec_null_decode ( ) {
283+ let v = Value :: from_bytes ( & [ 0x00u8 ] ) . unwrap ( ) ;
284+ assert_eq ! ( v, Value :: Null ) ;
285+ }
286+
287+ // -- String (tag 0x01, len:u32 LE, utf-8 bytes) --
288+
289+ #[ test]
290+ fn abi_vec_string_known_bytes ( ) {
291+ // "hi" → [0x01, 0x02 0x00 0x00 0x00, 0x68 0x69]
292+ let v = Value :: String ( "hi" . to_string ( ) ) ;
293+ let bytes = v. to_bytes ( ) ;
294+ let mut expected = vec ! [ 0x01u8 ] ;
295+ expected. extend_from_slice ( & le32 ( 2 ) ) ;
296+ expected. extend_from_slice ( b"hi" ) ;
297+ assert_eq ! ( bytes, expected) ;
298+ }
299+
300+ #[ test]
301+ fn abi_vec_string_decode_known_bytes ( ) {
302+ let mut raw = vec ! [ 0x01u8 ] ;
303+ raw. extend_from_slice ( & le32 ( 2 ) ) ;
304+ raw. extend_from_slice ( b"hi" ) ;
305+ let v = Value :: from_bytes ( & raw ) . unwrap ( ) ;
306+ assert_eq ! ( v, Value :: String ( "hi" . to_string( ) ) ) ;
307+ }
308+
309+ // -- Int (tag 0x02, i32 LE 4 bytes) --
310+
311+ #[ test]
312+ fn abi_vec_int_known_bytes ( ) {
313+ let v = Value :: Int ( 42 ) ;
314+ let bytes = v. to_bytes ( ) ;
315+ let mut expected = vec ! [ 0x02u8 ] ;
316+ expected. extend_from_slice ( & 42i32 . to_le_bytes ( ) ) ;
317+ assert_eq ! ( bytes, expected) ;
318+ }
319+
320+ #[ test]
321+ fn abi_vec_int_negative ( ) {
322+ let v = Value :: Int ( -1 ) ;
323+ let bytes = v. to_bytes ( ) ;
324+ let mut expected = vec ! [ 0x02u8 ] ;
325+ expected. extend_from_slice ( & ( -1i32 ) . to_le_bytes ( ) ) ;
326+ assert_eq ! ( bytes, expected) ;
327+ }
328+
329+ // -- Int8 (tag 0x03, i64 LE 8 bytes) --
330+
331+ #[ test]
332+ fn abi_vec_int8_known_bytes ( ) {
333+ let v = Value :: Int8 ( i64:: MAX ) ;
334+ let bytes = v. to_bytes ( ) ;
335+ let mut expected = vec ! [ 0x03u8 ] ;
336+ expected. extend_from_slice ( & i64:: MAX . to_le_bytes ( ) ) ;
337+ assert_eq ! ( bytes, expected) ;
338+ }
339+
340+ // -- BigInt (tag 0x04, len:u32 LE, signed-LE bytes) --
341+
342+ #[ test]
343+ fn abi_vec_bigint_uses_signed_le ( ) {
344+ // 1000 in signed-LE is [0xe8, 0x03]
345+ let n = BigInt :: from ( 1000u64 ) ;
346+ let le = n. to_signed_bytes_le ( ) ;
347+ assert_eq ! ( le, vec![ 0xe8u8 , 0x03 ] ) ;
348+
349+ let v = Value :: BigInt ( n) ;
350+ let bytes = v. to_bytes ( ) ;
351+ assert_eq ! ( bytes[ 0 ] , 0x04 ) ;
352+ let len = u32:: from_le_bytes ( bytes[ 1 ..5 ] . try_into ( ) . unwrap ( ) ) as usize ;
353+ assert_eq ! ( len, 2 ) ;
354+ assert_eq ! ( & bytes[ 5 ..] , & [ 0xe8u8 , 0x03 ] ) ;
355+ }
356+
357+ #[ test]
358+ fn abi_vec_bigint_decode_known_le_bytes ( ) {
359+ // hand-encoded 1000 as signed-LE
360+ let mut raw = vec ! [ 0x04u8 ] ;
361+ raw. extend_from_slice ( & le32 ( 2 ) ) ;
362+ raw. push ( 0xe8 ) ;
363+ raw. push ( 0x03 ) ;
364+ let v = Value :: from_bytes ( & raw ) . unwrap ( ) ;
365+ assert_eq ! ( v, Value :: BigInt ( BigInt :: from( 1000u64 ) ) ) ;
366+ }
367+
368+ #[ test]
369+ fn abi_vec_bigint_zero_len_zero ( ) {
370+ let v = Value :: BigInt ( BigInt :: from ( 0i32 ) ) ;
371+ let bytes = v. to_bytes ( ) ;
372+ // zero may encode as empty or as [0x00]; either is valid as long as decode round-trips
373+ let recovered = Value :: from_bytes ( & bytes) . unwrap ( ) ;
374+ assert_eq ! ( recovered, Value :: BigInt ( BigInt :: from( 0i32 ) ) ) ;
375+ }
376+
377+ // -- BigDecimal (tag 0x05, len:u32 LE, UTF-8 string) --
378+
379+ #[ test]
380+ fn abi_vec_bigdecimal_encodes_as_string ( ) {
381+ use std:: str:: FromStr ;
382+ let d = graph:: prelude:: BigDecimal :: from_str ( "3.14" ) . unwrap ( ) ;
383+ let v = Value :: BigDecimal ( d) ;
384+ let bytes = v. to_bytes ( ) ;
385+ assert_eq ! ( bytes[ 0 ] , 0x05 ) ;
386+ let len = u32:: from_le_bytes ( bytes[ 1 ..5 ] . try_into ( ) . unwrap ( ) ) as usize ;
387+ let s = std:: str:: from_utf8 ( & bytes[ 5 ..5 + len] ) . unwrap ( ) ;
388+ // must be a valid decimal string representation
389+ assert ! ( s. contains( '.' ) || s. chars( ) . all( |c| c. is_ascii_digit( ) || c == '-' || c == 'E' || c == 'e' ) ,
390+ "expected decimal string, got: {}" , s) ;
391+ }
392+
393+ #[ test]
394+ fn abi_vec_bigdecimal_decode_known_bytes ( ) {
395+ use std:: str:: FromStr ;
396+ let s = b"3.14" ;
397+ let mut raw = vec ! [ 0x05u8 ] ;
398+ raw. extend_from_slice ( & le32 ( s. len ( ) as u32 ) ) ;
399+ raw. extend_from_slice ( s) ;
400+ let v = Value :: from_bytes ( & raw ) . unwrap ( ) ;
401+ let expected = Value :: BigDecimal ( graph:: prelude:: BigDecimal :: from_str ( "3.14" ) . unwrap ( ) ) ;
402+ assert_eq ! ( v, expected) ;
403+ }
404+
405+ // -- Bool (tag 0x06) --
406+
407+ #[ test]
408+ fn abi_vec_bool_true_known_bytes ( ) {
409+ assert_eq ! ( Value :: Bool ( true ) . to_bytes( ) , [ 0x06u8 , 0x01 ] ) ;
410+ }
411+
412+ #[ test]
413+ fn abi_vec_bool_false_known_bytes ( ) {
414+ assert_eq ! ( Value :: Bool ( false ) . to_bytes( ) , [ 0x06u8 , 0x00 ] ) ;
415+ }
416+
417+ // -- Bytes (tag 0x07, len:u32 LE, raw bytes) --
418+
419+ #[ test]
420+ fn abi_vec_bytes_known_bytes ( ) {
421+ use graph:: data:: store:: scalar:: Bytes as StoreBytes ;
422+ let payload = vec ! [ 0xde , 0xad , 0xbe , 0xef ] ;
423+ let v = Value :: Bytes ( StoreBytes :: from ( payload. clone ( ) ) ) ;
424+ let encoded = v. to_bytes ( ) ;
425+ let mut expected = vec ! [ 0x07u8 ] ;
426+ expected. extend_from_slice ( & le32 ( 4 ) ) ;
427+ expected. extend_from_slice ( & payload) ;
428+ assert_eq ! ( encoded, expected) ;
429+ }
430+
431+ // -- Address (tag 0x08, 20 raw bytes, NO length prefix) --
432+
433+ #[ test]
434+ fn abi_vec_address_decode_tag_0x08 ( ) {
435+ // The SDK writes Address as tag 0x08 + 20 raw bytes (no length prefix).
436+ // graph-node decodes tag 0x08 as Value::Bytes(20 bytes).
437+ // Note: graph-node re-encodes Bytes as tag 0x07 (length-prefixed); the
438+ // asymmetry is intentional — 0x08 is a SDK-write/host-read optimisation.
439+ let addr = [ 0xabu8 ; 20 ] ;
440+ let mut raw = vec ! [ 0x08u8 ] ;
441+ raw. extend_from_slice ( & addr) ;
442+ assert_eq ! ( raw. len( ) , 21 ) ; // tag + 20 bytes, no length prefix
443+
444+ // graph-node must decode SDK-written 0x08 as Bytes carrying the 20-byte address
445+ let v = Value :: from_bytes ( & raw ) . unwrap ( ) ;
446+ if let Value :: Bytes ( b) = & v {
447+ assert_eq ! ( b. as_slice( ) , & addr) ;
448+ } else {
449+ panic ! ( "expected Bytes for Address tag, got {:?}" , v) ;
450+ }
451+ }
452+
453+ // -- Array (tag 0x09, len:u32 LE, tagged Values) --
454+
455+ #[ test]
456+ fn abi_vec_array_empty ( ) {
457+ let v = Value :: List ( vec ! [ ] ) ;
458+ let bytes = v. to_bytes ( ) ;
459+ let mut expected = vec ! [ 0x09u8 ] ;
460+ expected. extend_from_slice ( & le32 ( 0 ) ) ;
461+ assert_eq ! ( bytes, expected) ;
462+ }
463+
464+ #[ test]
465+ fn abi_vec_array_known_bytes ( ) {
466+ // [Int(1), Bool(true)]
467+ let v = Value :: List ( vec ! [ Value :: Int ( 1 ) , Value :: Bool ( true ) ] ) ;
468+ let bytes = v. to_bytes ( ) ;
469+ assert_eq ! ( bytes[ 0 ] , 0x09 ) ;
470+ let count = u32:: from_le_bytes ( bytes[ 1 ..5 ] . try_into ( ) . unwrap ( ) ) ;
471+ assert_eq ! ( count, 2 ) ;
472+ }
473+
474+ #[ test]
475+ fn abi_vec_array_decode_known_bytes ( ) {
476+ let mut raw = vec ! [ 0x09u8 ] ;
477+ raw. extend_from_slice ( & le32 ( 2 ) ) ;
478+ raw. push ( 0x02 ) ;
479+ raw. extend_from_slice ( & 1i32 . to_le_bytes ( ) ) ;
480+ raw. push ( 0x06 ) ;
481+ raw. push ( 0x01 ) ;
482+ let v = Value :: from_bytes ( & raw ) . unwrap ( ) ;
483+ assert_eq ! ( v, Value :: List ( vec![ Value :: Int ( 1 ) , Value :: Bool ( true ) ] ) ) ;
484+ }
485+
486+ // -- Cross-wire: spec worked example --
487+
488+ #[ test]
489+ fn abi_vec_spec_worked_example ( ) {
490+ // { id: "tx-1", value: 42, active: true } (spec section 4.6.1)
491+ // field_count: 3, field order unspecified but all fields must survive
492+ let mut data = EntityData :: new ( ) ;
493+ data. insert ( "id" . to_string ( ) , Value :: String ( "tx-1" . to_string ( ) ) ) ;
494+ data. insert ( "value" . to_string ( ) , Value :: Int ( 42 ) ) ;
495+ data. insert ( "active" . to_string ( ) , Value :: Bool ( true ) ) ;
496+
497+ let bytes = data. to_bytes ( ) ;
498+
499+ // field count must be 3
500+ let count = u32:: from_le_bytes ( bytes[ 0 ..4 ] . try_into ( ) . unwrap ( ) ) ;
501+ assert_eq ! ( count, 3 ) ;
502+
503+ let recovered = EntityData :: from_bytes ( & bytes) . unwrap ( ) ;
504+ assert_eq ! ( recovered. get( "id" ) , Some ( & Value :: String ( "tx-1" . to_string( ) ) ) ) ;
505+ assert_eq ! ( recovered. get( "value" ) , Some ( & Value :: Int ( 42 ) ) ) ;
506+ assert_eq ! ( recovered. get( "active" ) , Some ( & Value :: Bool ( true ) ) ) ;
507+ }
259508}
0 commit comments