1515package conway_test
1616
1717import (
18+ "bytes"
1819 "encoding/hex"
20+ "fmt"
1921 "math/big"
22+ "os"
23+ "path/filepath"
2024 "reflect"
25+ "regexp"
2126 "strings"
2227 "testing"
2328
@@ -27,6 +32,7 @@ import (
2732 "github.com/blinklabs-io/gouroboros/ledger/conway"
2833 "github.com/blinklabs-io/gouroboros/ledger/mary"
2934 "github.com/blinklabs-io/gouroboros/ledger/shelley"
35+ fxcbor "github.com/fxamacker/cbor/v2"
3036 "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano"
3137)
3238
@@ -734,3 +740,127 @@ func TestConwayTransaction_Utxorpc(t *testing.T) {
734740 t .Error ("Expected non-empty transaction hash" )
735741 }
736742}
743+
744+ func isValidHexString (s string ) error {
745+ if len (s )% 2 != 0 {
746+ return fmt .Errorf ("hex string must have even length, got %d" , len (s ))
747+ }
748+ matched , err := regexp .MatchString ("^[0-9a-fA-F]+$" , s )
749+ if err != nil {
750+ return fmt .Errorf ("regex validation failed: %v" , err )
751+ }
752+ if ! matched {
753+ return fmt .Errorf ("hex string contains invalid characters" )
754+ }
755+ return nil
756+ }
757+
758+ func TestConwayBlock_CborRoundTrip_UsingStandardMarshal (t * testing.T ) {
759+ // Read the hex-encoded CBOR string for a Conway block
760+ filePath := filepath .Join ("testdata" , "conway_block.cbor.hex" )
761+ dataHex , err := os .ReadFile (filePath )
762+ if err != nil {
763+ t .Fatalf ("Failed to read test file 'conway_block.cbor.hex': %v" , err )
764+ }
765+
766+ // Validate the hex string before decoding
767+ hexStr := strings .TrimSpace (string (dataHex ))
768+ if err := isValidHexString (hexStr ); err != nil {
769+ t .Fatalf ("Invalid Conway block hex string: %v" , err )
770+ }
771+
772+ // Decode the hex string into CBOR bytes
773+ dataBytes , err := hex .DecodeString (hexStr )
774+ if err != nil {
775+ t .Fatalf ("Failed to decode Conway block hex string into CBOR bytes: %v" , err )
776+ }
777+
778+ // Deserialize CBOR bytes into ConwayBlock struct
779+ var block conway.ConwayBlock
780+ err = block .UnmarshalCBOR (dataBytes )
781+ if err != nil {
782+ t .Fatalf ("Failed to unmarshal CBOR data into ConwayBlock: %v" , err )
783+ }
784+
785+ // Re-marshal the struct back to CBOR using inbuilt cbor.Marshal
786+ encoded , err := fxcbor .Marshal (block )
787+ if encoded == nil {
788+ t .Fatal ("Re-encoded CBOR from ConwayBlock is nil" )
789+ }
790+ if len (encoded ) == 0 {
791+ t .Fatal ("Re-encoded CBOR from ConwayBlock is empty" )
792+ }
793+
794+ if ! bytes .Equal (dataBytes , encoded ) {
795+ t .Errorf ("CBOR round-trip mismatch for Conway block\n Original CBOR (hex): %x\n Re-encoded CBOR (hex): %x" , dataBytes , encoded )
796+
797+ // Check from which byte it differs
798+ diffIndex := - 1
799+ for i := 0 ; i < len (dataBytes ) && i < len (encoded ); i ++ {
800+ if dataBytes [i ] != encoded [i ] {
801+ diffIndex = i
802+ break
803+ }
804+ }
805+ if diffIndex != - 1 {
806+ t .Logf ("First mismatch at byte index: %d" , diffIndex )
807+ t .Logf ("Original byte: 0x%02x, Re-encoded byte: 0x%02x" , dataBytes [diffIndex ], encoded [diffIndex ])
808+ } else {
809+ t .Logf ("Length mismatch: original length = %d, re-encoded length = %d" , len (dataBytes ), len (encoded ))
810+ }
811+ }
812+
813+ //Save re-encoded CBOR hex to a new file for inspection
814+ newHexPath := filepath .Join ("testdata" , "conway_block_reencoded.cbor.hex" )
815+ if err := os .WriteFile (newHexPath , []byte (hex .EncodeToString (encoded )), 0644 ); err != nil {
816+ t .Errorf ("Failed to write re-encoded CBOR hex to file: %v" , err )
817+ }
818+ }
819+
820+ func TestConwayBlock_CborRoundTrip_UsingCustomEncode (t * testing.T ) {
821+ // Read the hex-encoded CBOR string for a Conway block
822+ filePath := filepath .Join ("testdata" , "conway_block.cbor.hex" )
823+ dataHex , err := os .ReadFile (filePath )
824+ if err != nil {
825+ t .Fatalf ("Failed to read test file 'conway_block.cbor.hex': %v" , err )
826+ }
827+
828+ // Validate the hex string before decoding
829+ hexStr := strings .TrimSpace (string (dataHex ))
830+ if err := isValidHexString (hexStr ); err != nil {
831+ t .Fatalf ("Invalid Conway block hex string: %v" , err )
832+ }
833+
834+ // Decode the hex string into CBOR bytes
835+ dataBytes , err := hex .DecodeString (hexStr )
836+ if err != nil {
837+ t .Fatalf ("Failed to decode Conway block hex string into CBOR bytes: %v" , err )
838+ }
839+
840+ // Deserialize CBOR bytes into ConwayBlock struct
841+ var block conway.ConwayBlock
842+ err = block .UnmarshalCBOR (dataBytes )
843+ if err != nil {
844+ t .Fatalf ("Failed to unmarshal CBOR data into ConwayBlock: %v" , err )
845+ }
846+
847+ // Re-encode using the cbor Encode function
848+ encoded , err := cbor .Encode (block )
849+ if err != nil {
850+ t .Fatalf ("Failed to marshal ConwayBlock using custom encode function: %v" , err )
851+ }
852+ if encoded == nil || len (encoded ) == 0 {
853+ t .Fatal ("Custom encoded CBOR from ConwayBlock is nil or empty" )
854+ }
855+
856+ // Ensure the original and re-encoded CBOR bytes are identical
857+ if ! bytes .Equal (dataBytes , encoded ) {
858+ t .Errorf ("Custom CBOR round-trip mismatch for Conway block\n Original CBOR (hex): %x\n Custom Encoded CBOR (hex): %x" , dataBytes , encoded )
859+ }
860+
861+ // Save the re-encoded CBOR for comparison
862+ newHexPath := filepath .Join ("testdata" , "conway_block_reencoded.custom.hex" )
863+ if err := os .WriteFile (newHexPath , []byte (hex .EncodeToString (encoded )), 0644 ); err != nil {
864+ t .Errorf ("Failed to write custom re-encoded CBOR hex to file: %v" , err )
865+ }
866+ }
0 commit comments