1
- from typing import Dict , List
1
+ import logging
2
2
3
3
import base58
4
4
import cid
5
- import varint
6
5
7
6
from ..codecs import CodecBase
8
- from . import LENGTH_PREFIXED_VAR_SIZE
9
7
from ..exceptions import BinaryParseError
8
+ from . import LENGTH_PREFIXED_VAR_SIZE
9
+
10
+ logger = logging .getLogger (__name__ )
10
11
11
12
SIZE = LENGTH_PREFIXED_VAR_SIZE
12
13
IS_PATH = False
13
14
14
15
15
16
# Spec: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation
16
- CIDv0_PREFIX_TO_LENGTH : Dict [str , List [int ]] = {
17
+ CIDv0_PREFIX_TO_LENGTH : dict [str , list [int ]] = {
17
18
# base58btc prefixes for valid lengths 1 - 42 with the identity "hash" function
18
19
"12" : [5 , 12 , 19 , 23 , 30 , 41 , 52 , 56 ],
19
20
"13" : [9 , 16 , 34 , 45 ],
@@ -75,8 +76,15 @@ def _is_binary_cidv0_multihash(buf: bytes) -> bool:
75
76
"""Check if the given bytes represent a CIDv0 multihash."""
76
77
try :
77
78
# CIDv0 is just a base58btc encoded multihash
78
- decoded = base58 .b58decode (base58 .b58encode (buf ).decode ("ascii" ))
79
- return len (decoded ) == len (buf ) and decoded == buf
79
+ # The first byte is the hash function code, second byte is the length
80
+ if len (buf ) < 2 :
81
+ return False
82
+ hash_code = buf [0 ]
83
+ length = buf [1 ]
84
+ if len (buf ) != length + 2 : # +2 for the hash code and length bytes
85
+ return False
86
+ # For CIDv0, we only support sha2-256 (0x12) and identity (0x00)
87
+ return hash_code in (0x12 , 0x00 )
80
88
except Exception :
81
89
return False
82
90
@@ -85,62 +93,84 @@ class Codec(CodecBase):
85
93
SIZE = SIZE
86
94
IS_PATH = IS_PATH
87
95
88
- def to_bytes (self , proto , value : str ) -> bytes :
96
+ def to_bytes (self , proto , string : str ) -> bytes :
89
97
"""Convert a CID string to its binary representation."""
90
- if not value :
98
+ if not string :
91
99
raise ValueError ("CID string cannot be empty" )
92
100
101
+ logger .debug (f"[DEBUG CID to_bytes] Input value: { string } " )
102
+
93
103
# First try to parse as CIDv0 (base58btc encoded multihash)
94
104
try :
95
- decoded = base58 .b58decode (value )
105
+ decoded = base58 .b58decode (string )
96
106
if _is_binary_cidv0_multihash (decoded ):
97
- # Add length prefix for CIDv0
98
- return varint .encode (len (decoded )) + decoded
99
- except Exception :
100
- pass
107
+ logger .debug (f"[DEBUG CID to_bytes] Parsed as CIDv0: { decoded .hex ()} " )
108
+ # Do not add length prefix here; the framework handles it
109
+ return decoded
110
+ except Exception as e :
111
+ logger .debug (f"[DEBUG CID to_bytes] Failed to parse as CIDv0: { e } " )
101
112
102
113
# If not CIDv0, try to parse as CIDv1
103
114
try :
104
- parsed = cid .make_cid (value )
105
- # Add length prefix for CIDv1
106
- return varint .encode (len (parsed .buffer )) + parsed .buffer
107
- except ValueError :
108
- raise ValueError (f"Invalid CID: { value } " )
115
+ parsed = cid .make_cid (string )
116
+
117
+ # Do not add length prefix here; the framework handles it
118
+ if not isinstance (parsed .buffer , bytes ):
119
+ raise ValueError ("CID buffer must be bytes" )
120
+ return parsed .buffer
121
+ except ValueError as e :
122
+ logger .debug (f"[DEBUG CID to_bytes] Failed to parse as CIDv1: { e } " )
123
+ raise ValueError (f"Invalid CID: { string } " )
109
124
110
125
def to_string (self , proto , buf : bytes ) -> str :
111
126
"""Convert a binary CID to its string representation."""
112
127
if not buf :
113
128
raise ValueError ("CID buffer cannot be empty" )
114
129
130
+ logger .debug (f"[DEBUG CID to_string] Input buffer: { buf .hex ()} " )
131
+ logger .debug (f"[DEBUG CID to_string] Protocol: { proto .name } " )
132
+
115
133
expected_codec = PROTO_NAME_TO_CIDv1_CODEC .get (proto .name )
134
+ logger .debug (f"[DEBUG CID to_string] Expected codec: { expected_codec } " )
116
135
117
136
try :
118
- if _is_binary_cidv0_multihash (buf ): # CIDv0
119
- if not expected_codec :
120
- # Simply encode as base58btc as there is nothing better to do
121
- return base58 .b58encode (buf ).decode ("ascii" )
122
-
123
- # "Implementations SHOULD display peer IDs using the first (raw
124
- # base58btc encoded multihash) format until the second format is
125
- # widely supported."
126
- return base58 .b58encode (buf ).decode ("ascii" )
127
- else : # CIDv1+
128
- parsed = cid .from_bytes (buf )
129
-
130
- # Ensure CID has correct codec for protocol
131
- if expected_codec and parsed .codec != expected_codec :
132
- raise ValueError (
133
- '"{0}" multiaddr CIDs must use the "{1}" multicodec' .format (
134
- proto .name , expected_codec
135
- )
137
+ # First try to parse as CIDv0
138
+ if _is_binary_cidv0_multihash (buf ):
139
+ result = base58 .b58encode (buf ).decode ("ascii" )
140
+ logger .debug (f"[DEBUG CID to_string] Parsed as CIDv0: { result } " )
141
+ return result
142
+
143
+ # If not CIDv0, try to parse as CIDv1
144
+ parsed = cid .from_bytes (buf )
145
+ logger .debug (f"[DEBUG CID to_string] Parsed as CIDv1: { parsed } " )
146
+
147
+ # Ensure CID has correct codec for protocol
148
+ if expected_codec and parsed .codec != expected_codec :
149
+ raise ValueError (
150
+ '"{}" multiaddr CIDs must use the "{}" multicodec' .format (
151
+ proto .name , expected_codec
136
152
)
137
-
138
- # "Implementations SHOULD display peer IDs using the first (raw
139
- # base58btc encoded multihash) format until the second format is
140
- # widely supported."
141
- if expected_codec and _is_binary_cidv0_multihash (parsed .multihash ):
142
- return base58 .b58encode (parsed .multihash ).decode ("ascii" )
143
-
144
- return parsed .encode ("base32" ).decode ("ascii" )
153
+ )
154
+
155
+ # For peer IDs (p2p/ipfs), always try to use CIDv0 format if possible
156
+ if expected_codec :
157
+ # Try to convert to CIDv0 format
158
+ try :
159
+ # Extract the multihash bytes
160
+ multihash = parsed .multihash
161
+ logger .debug (f"[DEBUG CID to_string] Extracted multihash: { multihash .hex ()} " )
162
+ # Check if it's a valid CIDv0 multihash
163
+ if _is_binary_cidv0_multihash (multihash ):
164
+ result = base58 .b58encode (multihash ).decode ("ascii" )
165
+ logger .debug (f"[DEBUG CID to_string] Converted to CIDv0: { result } " )
166
+ return result
167
+ except Exception as e :
168
+ logger .debug (f"[DEBUG CID to_string] Failed to convert to CIDv0: { e } " )
169
+
170
+ # If we can't convert to CIDv0, use base32 CIDv1 format
171
+ result = parsed .encode ("base32" ).decode ("ascii" )
172
+ logger .debug (f"[DEBUG CID to_string] Using CIDv1 format: { result } " )
173
+ return result
145
174
except Exception as e :
175
+ logger .debug (f"[DEBUG CID to_string] Error: { e } " )
146
176
raise BinaryParseError (str (e ), buf , proto .name , e ) from e
0 commit comments