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