@@ -265,40 +265,40 @@ private string HashBlake2b256(byte[] data)
265265 }
266266
267267 /// <summary>
268- /// Serializes a deploy header to bytes (simplified Casper serialization)
268+ /// Serializes a deploy header to bytes according to Casper bytesrepr format
269269 /// </summary>
270270 private byte [ ] SerializeDeployHeader ( DeployHeader header )
271271 {
272272 var parts = new List < byte > ( ) ;
273273
274- // Account (public key with length prefix)
274+ // Account (public key: just the bytes, no length prefix)
275+ // PublicKey format: [algo_tag(1 byte)][key_bytes(32 or 33 bytes)]
275276 var accountBytes = CryptoHelper . HexToBytes ( header . Account ) ;
276- parts . AddRange ( BitConverter . GetBytes ( ( uint ) accountBytes . Length ) ) ;
277277 parts . AddRange ( accountBytes ) ;
278278
279- // Timestamp (as milliseconds since epoch)
279+ // Timestamp (as milliseconds since epoch, u64 LE )
280280 var timestamp = DateTime . Parse ( header . Timestamp ) . ToUniversalTime ( ) ;
281281 var epochMs = ( long ) ( timestamp - new DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 , DateTimeKind . Utc ) ) . TotalMilliseconds ;
282- parts . AddRange ( BitConverter . GetBytes ( epochMs ) ) ;
282+ parts . AddRange ( BitConverter . GetBytes ( ( ulong ) epochMs ) ) ;
283283
284- // TTL
285- parts . AddRange ( BitConverter . GetBytes ( header . TTL ) ) ;
284+ // TTL (u64 LE)
285+ parts . AddRange ( BitConverter . GetBytes ( ( ulong ) header . TTL ) ) ;
286286
287- // Gas price
288- parts . AddRange ( BitConverter . GetBytes ( header . GasPrice ) ) ;
287+ // Gas price (u64 LE)
288+ parts . AddRange ( BitConverter . GetBytes ( ( ulong ) header . GasPrice ) ) ;
289289
290- // Body hash
290+ // Body hash (32 bytes, no length prefix)
291291 var bodyHashBytes = CryptoHelper . HexToBytes ( header . BodyHash ) ;
292292 parts . AddRange ( bodyHashBytes ) ;
293293
294- // Dependencies count and hashes
294+ // Dependencies count (u32 LE) and hashes
295295 parts . AddRange ( BitConverter . GetBytes ( ( uint ) header . Dependencies . Length ) ) ;
296296 foreach ( var dep in header . Dependencies )
297297 {
298298 parts . AddRange ( CryptoHelper . HexToBytes ( dep ) ) ;
299299 }
300300
301- // Chain name (length-prefixed string)
301+ // Chain name (length-prefixed string, u32 LE )
302302 var chainNameBytes = Encoding . UTF8 . GetBytes ( header . ChainName ) ;
303303 parts . AddRange ( BitConverter . GetBytes ( ( uint ) chainNameBytes . Length ) ) ;
304304 parts . AddRange ( chainNameBytes ) ;
@@ -361,30 +361,122 @@ private byte[] SerializeExecutableDeployItem(ExecutableDeployItem item)
361361 }
362362
363363 /// <summary>
364- /// Serializes runtime arguments
364+ /// Serializes runtime arguments according to Casper bytesrepr format
365+ /// Format: [count][arg1][arg2]...
366+ /// Each arg: [name_len][name][value_bytes_len][value_bytes][cltype_bytes]
365367 /// </summary>
366368 private byte [ ] SerializeRuntimeArgs ( RuntimeArg [ ] args )
367369 {
368370 var parts = new List < byte > ( ) ;
369371 args = args ?? Array . Empty < RuntimeArg > ( ) ;
370372
371- // Args count
373+ // Args count (u32 LE)
372374 parts . AddRange ( BitConverter . GetBytes ( ( uint ) args . Length ) ) ;
373375
374376 foreach ( var arg in args )
375377 {
376- // Name (length-prefixed)
378+ // Name (length-prefixed string )
377379 var nameBytes = Encoding . UTF8 . GetBytes ( arg . Name ?? "" ) ;
378380 parts . AddRange ( BitConverter . GetBytes ( ( uint ) nameBytes . Length ) ) ;
379381 parts . AddRange ( nameBytes ) ;
380382
381- // Value bytes
383+ // CLValue: [bytes_len][ bytes][cltype_serialized]
382384 var valueBytes = CryptoHelper . HexToBytes ( arg . Value ? . Bytes ?? "" ) ;
385+ var clTypeBytes = SerializeCLType ( arg . Value ? . CLType ?? "Unit" ) ;
386+
387+ // Value bytes length + bytes
383388 parts . AddRange ( BitConverter . GetBytes ( ( uint ) valueBytes . Length ) ) ;
384389 parts . AddRange ( valueBytes ) ;
390+
391+ // CLType (no length prefix, directly appended)
392+ parts . AddRange ( clTypeBytes ) ;
385393 }
386394
387395 return parts . ToArray ( ) ;
388396 }
397+
398+ /// <summary>
399+ /// Serializes CLType to bytes according to Casper spec
400+ /// </summary>
401+ private byte [ ] SerializeCLType ( string clType )
402+ {
403+ // Simple types have a single byte tag
404+ switch ( clType )
405+ {
406+ case "Bool" : return new byte [ ] { 0 } ;
407+ case "I32" : return new byte [ ] { 1 } ;
408+ case "I64" : return new byte [ ] { 2 } ;
409+ case "U8" : return new byte [ ] { 3 } ;
410+ case "U32" : return new byte [ ] { 4 } ;
411+ case "U64" : return new byte [ ] { 5 } ;
412+ case "U128" : return new byte [ ] { 6 } ;
413+ case "U256" : return new byte [ ] { 7 } ;
414+ case "U512" : return new byte [ ] { 8 } ;
415+ case "Unit" : return new byte [ ] { 9 } ;
416+ case "String" : return new byte [ ] { 10 } ;
417+ case "Key" : return new byte [ ] { 11 } ;
418+ case "URef" : return new byte [ ] { 12 } ;
419+ case "PublicKey" : return new byte [ ] { 22 } ;
420+ }
421+
422+ // Option type: tag 13 + inner type
423+ if ( clType == "Option" )
424+ {
425+ return new byte [ ] { 13 , 5 } ; // Option(U64) for transfer id
426+ }
427+ if ( clType . StartsWith ( "Option(" ) && clType . EndsWith ( ")" ) )
428+ {
429+ var inner = clType . Substring ( 7 , clType . Length - 8 ) ;
430+ var innerBytes = SerializeCLType ( inner ) ;
431+ var result = new byte [ 1 + innerBytes . Length ] ;
432+ result [ 0 ] = 13 ; // Option tag
433+ Buffer . BlockCopy ( innerBytes , 0 , result , 1 , innerBytes . Length ) ;
434+ return result ;
435+ }
436+
437+ // List type: tag 14 + inner type
438+ if ( clType . StartsWith ( "List(" ) && clType . EndsWith ( ")" ) )
439+ {
440+ var inner = clType . Substring ( 5 , clType . Length - 6 ) ;
441+ var innerBytes = SerializeCLType ( inner ) ;
442+ var result = new byte [ 1 + innerBytes . Length ] ;
443+ result [ 0 ] = 14 ; // List tag
444+ Buffer . BlockCopy ( innerBytes , 0 , result , 1 , innerBytes . Length ) ;
445+ return result ;
446+ }
447+
448+ // ByteArray - tag 15 + size (u32)
449+ if ( clType . StartsWith ( "ByteArray(" ) && clType . EndsWith ( ")" ) )
450+ {
451+ var sizeStr = clType . Substring ( 10 , clType . Length - 11 ) ;
452+ var size = uint . Parse ( sizeStr ) ;
453+ var result = new byte [ 5 ] ;
454+ result [ 0 ] = 15 ; // ByteArray tag
455+ Buffer . BlockCopy ( BitConverter . GetBytes ( size ) , 0 , result , 1 , 4 ) ;
456+ return result ;
457+ }
458+
459+ // Map type: tag 17 + key type + value type
460+ if ( clType . StartsWith ( "Map(" ) && clType . EndsWith ( ")" ) )
461+ {
462+ var inner = clType . Substring ( 4 , clType . Length - 5 ) ;
463+ var comma = inner . IndexOf ( ',' ) ;
464+ if ( comma > 0 )
465+ {
466+ var keyType = inner . Substring ( 0 , comma ) . Trim ( ) ;
467+ var valueType = inner . Substring ( comma + 1 ) . Trim ( ) ;
468+ var keyBytes = SerializeCLType ( keyType ) ;
469+ var valueBytes = SerializeCLType ( valueType ) ;
470+ var result = new byte [ 1 + keyBytes . Length + valueBytes . Length ] ;
471+ result [ 0 ] = 17 ; // Map tag
472+ Buffer . BlockCopy ( keyBytes , 0 , result , 1 , keyBytes . Length ) ;
473+ Buffer . BlockCopy ( valueBytes , 0 , result , 1 + keyBytes . Length , valueBytes . Length ) ;
474+ return result ;
475+ }
476+ }
477+
478+ // Default: Unit
479+ return new byte [ ] { 9 } ;
480+ }
389481 }
390482}
0 commit comments