|
1 | 1 | import base58
|
2 | 2 | import cid
|
| 3 | +from typing import Dict, List |
| 4 | +from ..codecs import CodecBase |
3 | 5 |
|
4 | 6 | from . import LENGTH_PREFIXED_VAR_SIZE
|
5 | 7 |
|
6 |
| - |
7 | 8 | SIZE = LENGTH_PREFIXED_VAR_SIZE
|
8 | 9 | IS_PATH = False
|
9 | 10 |
|
10 | 11 |
|
11 | 12 | # Spec: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation
|
12 |
| -CIDv0_PREFIX_TO_LENGTH = { |
13 |
| - # base58btc prefixes for valid lengths 1 – 42 with the identity “hash” function |
| 13 | +CIDv0_PREFIX_TO_LENGTH: Dict[str, List[int]] = { |
| 14 | + # base58btc prefixes for valid lengths 1 – 42 with the identity "hash" function |
14 | 15 | '12': [5, 12, 19, 23, 30, 41, 52, 56],
|
15 | 16 | '13': [9, 16, 34, 45],
|
16 | 17 | '14': [27, 38, 49, 60],
|
|
62 | 63 | 'Qm': [46],
|
63 | 64 | }
|
64 | 65 |
|
65 |
| -PROTO_NAME_TO_CIDv1_CODEC = { |
66 |
| - # The “p2p” multiaddr protocol requires all keys to use the “libp2p-key” multicodec |
| 66 | +PROTO_NAME_TO_CIDv1_CODEC: Dict[str, str] = { |
| 67 | + # The "p2p" multiaddr protocol requires all keys to use the "libp2p-key" multicodec |
67 | 68 | "p2p": "libp2p-key",
|
68 | 69 | }
|
69 | 70 |
|
70 | 71 |
|
71 |
| -def to_bytes(proto, string): |
72 |
| - expected_codec = PROTO_NAME_TO_CIDv1_CODEC.get(proto.name) |
73 |
| - |
74 |
| - if len(string) in CIDv0_PREFIX_TO_LENGTH.get(string[0:2], ()): # CIDv0 |
75 |
| - # Upgrade the wire (binary) representation of any received CIDv0 string |
76 |
| - # to CIDv1 if we can determine which multicodec value to use |
77 |
| - if expected_codec: |
78 |
| - return cid.make_cid(1, expected_codec, base58.b58decode(string)).buffer |
79 |
| - |
80 |
| - return base58.b58decode(string) |
81 |
| - else: # CIDv1+ |
82 |
| - parsed = cid.from_string(string) |
83 |
| - |
84 |
| - # Ensure CID has correct codec for protocol |
85 |
| - if expected_codec and parsed.codec != expected_codec: |
86 |
| - raise ValueError("“{0}” multiaddr CIDs must use the “{1}” multicodec" |
87 |
| - .format(proto.name, expected_codec)) |
88 |
| - |
89 |
| - return parsed.buffer |
90 |
| - |
91 |
| - |
92 |
| -def _is_binary_cidv0_multihash(buf): |
| 72 | +class Codec(CodecBase): |
| 73 | + SIZE = SIZE |
| 74 | + IS_PATH = IS_PATH |
| 75 | + |
| 76 | + def to_bytes(self, proto, string): |
| 77 | + expected_codec = PROTO_NAME_TO_CIDv1_CODEC.get(proto.name) |
| 78 | + |
| 79 | + if len(string) in CIDv0_PREFIX_TO_LENGTH.get(string[0:2], ()): # CIDv0 |
| 80 | + # Upgrade the wire (binary) representation of any received CIDv0 string |
| 81 | + # to CIDv1 if we can determine which multicodec value to use |
| 82 | + if expected_codec: |
| 83 | + cid_obj = cid.make_cid(1, expected_codec, base58.b58decode(string)) |
| 84 | + assert isinstance(cid_obj.buffer, bytes) |
| 85 | + return cid_obj.buffer |
| 86 | + |
| 87 | + return base58.b58decode(string) |
| 88 | + else: # CIDv1+ |
| 89 | + parsed = cid.from_string(string) |
| 90 | + |
| 91 | + # Ensure CID has correct codec for protocol |
| 92 | + if expected_codec and parsed.codec != expected_codec: |
| 93 | + raise ValueError( |
| 94 | + '"{0}" multiaddr CIDs must use the "{1}" multicodec'.format( |
| 95 | + proto.name, expected_codec |
| 96 | + ) |
| 97 | + ) |
| 98 | + |
| 99 | + return parsed.buffer |
| 100 | + |
| 101 | + def to_string(self, proto, buf): |
| 102 | + expected_codec = PROTO_NAME_TO_CIDv1_CODEC.get(proto.name) |
| 103 | + |
| 104 | + if _is_binary_cidv0_multihash(buf): # CIDv0 |
| 105 | + if not expected_codec: |
| 106 | + # Simply encode as base58btc as there is nothing better to do |
| 107 | + return base58.b58encode(buf).decode('ascii') |
| 108 | + |
| 109 | + # "Implementations SHOULD display peer IDs using the first (raw |
| 110 | + # base58btc encoded multihash) format until the second format is |
| 111 | + # widely supported." |
| 112 | + # |
| 113 | + # In the future the following line should instead convert the multihash |
| 114 | + # to CIDv1 and with the `expected_codec` and wrap it in base32: |
| 115 | + # return cid.make_cid(1, expected_codec, buf).encode("base32").decode("ascii") |
| 116 | + return base58.b58encode(buf).decode("ascii") |
| 117 | + else: # CIDv1+ |
| 118 | + parsed = cid.from_bytes(buf) |
| 119 | + |
| 120 | + # Ensure CID has correct codec for protocol |
| 121 | + if expected_codec and parsed.codec != expected_codec: |
| 122 | + raise ValueError( |
| 123 | + '"{0}" multiaddr CIDs must use the "{1}" multicodec'.format( |
| 124 | + proto.name, expected_codec |
| 125 | + ) |
| 126 | + ) |
| 127 | + |
| 128 | + # "Implementations SHOULD display peer IDs using the first (raw |
| 129 | + # base58btc encoded multihash) format until the second format is |
| 130 | + # widely supported." |
| 131 | + if expected_codec and _is_binary_cidv0_multihash(parsed.multihash): |
| 132 | + return base58.b58encode(parsed.multihash).decode("ascii") |
| 133 | + |
| 134 | + return parsed.encode("base32").decode("ascii") |
| 135 | + |
| 136 | + |
| 137 | +def _is_binary_cidv0_multihash(buf: bytes) -> bool: |
93 | 138 | if buf.startswith(b"\x12\x20") and len(buf) == 34: # SHA2-256
|
94 | 139 | return True
|
95 | 140 |
|
96 | 141 | if (buf[0] == 0x00 and buf[1] in range(43)) and len(buf) == (buf[1] + 2): # Identity hash
|
97 | 142 | return True
|
98 | 143 |
|
99 | 144 | return False
|
100 |
| - |
101 |
| - |
102 |
| -def to_string(proto, buf): |
103 |
| - expected_codec = PROTO_NAME_TO_CIDv1_CODEC.get(proto.name) |
104 |
| - |
105 |
| - if _is_binary_cidv0_multihash(buf): # CIDv0 |
106 |
| - if not expected_codec: |
107 |
| - # Simply encode as base58btc as there is nothing better to do |
108 |
| - return base58.b58encode(buf).decode('ascii') |
109 |
| - |
110 |
| - # “Implementations SHOULD display peer IDs using the first (raw |
111 |
| - # base58btc encoded multihash) format until the second format is |
112 |
| - # widely supported.” |
113 |
| - # |
114 |
| - # In the future the following line should instead convert the multihash |
115 |
| - # to CIDv1 and with the `expected_codec` and wrap it in base32: |
116 |
| - # return cid.make_cid(1, expected_codec, buf).encode("base32").decode("ascii") |
117 |
| - return base58.b58encode(buf).decode("ascii") |
118 |
| - else: # CIDv1+ |
119 |
| - parsed = cid.from_bytes(buf) |
120 |
| - |
121 |
| - # Ensure CID has correct codec for protocol |
122 |
| - if expected_codec and parsed.codec != expected_codec: |
123 |
| - raise ValueError("“{0}” multiaddr CIDs must use the “{1}” multicodec" |
124 |
| - .format(proto.name, expected_codec)) |
125 |
| - |
126 |
| - # “Implementations SHOULD display peer IDs using the first (raw |
127 |
| - # base58btc encoded multihash) format until the second format is |
128 |
| - # widely supported.” |
129 |
| - if expected_codec and _is_binary_cidv0_multihash(parsed.multihash): |
130 |
| - return base58.b58encode(parsed.multihash).decode("ascii") |
131 |
| - |
132 |
| - return parsed.encode("base32").decode("ascii") |
|
0 commit comments