Skip to content

Commit 94660e7

Browse files
committed
Merge #1809: fix(deps): bencode library
091ce51 fix(deps): bencode library (roshii) Pull request description: Migrate from abandoned `bencoder.pyx` to `fastbencode`. Update minimum Python version requirement to 3.9 (with 3.8 effectively eol since a year) Python 3.13 compatibility will require other dependencies bumping such as `twisted` in #1732 Closes: #1805 Top commit has no ACKs. Tree-SHA512: b498fdead26b0f6b7b97448b3eee0a5b09ec379a63dbfa69b2b1c1d7e02f30e20ab15c52f7c4223f68189e2d244bf49d04dde4dbb2ae2f0cde865d4c5e0dc6da
2 parents 8b1cd5a + 091ce51 commit 94660e7

File tree

4 files changed

+42
-11
lines changed

4 files changed

+42
-11
lines changed

.github/workflows/unittests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
strategy:
1010
matrix:
1111
os: [macos-13, ubuntu-latest]
12-
python-version: ["3.8", "3.12"]
12+
python-version: ["3.9", "3.12"]
1313
bitcoind-version: ["29.2"]
1414

1515
steps:

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name = "joinmarket"
77
version = "0.9.12dev"
88
description = "Joinmarket client library for Bitcoin coinjoins"
99
readme = "README.md"
10-
requires-python = ">=3.8,<3.13"
10+
requires-python = ">=3.9,<3.13"
1111
license = {file = "LICENSE"}
1212
dependencies = [
1313
"chromalog==1.0.5",
@@ -24,7 +24,7 @@ jmbitcoin = [
2424
jmclient = [
2525
"argon2_cffi==21.3.0",
2626
"autobahn==20.12.3",
27-
"bencoder.pyx==3.0.1",
27+
"fastbencode==0.3.6",
2828
"klein==20.6.0",
2929
"mnemonic==0.20",
3030
"pyjwt==2.4.0",

src/jmclient/storage.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import atexit
12
import os
23
import shutil
3-
import atexit
4-
import bencoder
54
from hashlib import sha256
5+
from typing import Any
6+
67
from argon2 import low_level
7-
from jmbase import aes_cbc_encrypt, aes_cbc_decrypt
8+
from fastbencode import bdecode, bencode_utf8
9+
10+
from jmbase import aes_cbc_decrypt, aes_cbc_encrypt
11+
812
from .support import get_random_bytes
913

1014

@@ -223,12 +227,12 @@ def get_location(self):
223227
return self.path
224228

225229
@staticmethod
226-
def _serialize(data):
227-
return bencoder.bencode(data)
230+
def _serialize(data: Any) -> bytes:
231+
return bencode_utf8(data)
228232

229233
@staticmethod
230-
def _deserialize(data):
231-
return bencoder.bdecode(data)
234+
def _deserialize(data: bytes) -> Any:
235+
return bdecode(data)
232236

233237
def _encrypt_file(self, data):
234238
if not self.is_encrypted():

test/jmclient/test_storage.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from jmclient import storage
32
import pytest
43

@@ -81,6 +80,7 @@ def test_storage_invalid():
8180
MockStorage(b'garbagefile', __file__, b'password')
8281
pytest.fail("Non-wallet file, encrypted")
8382

83+
8484
def test_storage_readonly():
8585
s = MockStorage(None, 'nonexistant', b'password', create=True)
8686
s = MockStorage(s.file_data, __file__, b'password', read_only=True)
@@ -136,3 +136,30 @@ def test_storage_lock(tmpdir):
136136
s._create_lock()
137137
pytest.fail("It should not be possible to re-create a lock")
138138

139+
140+
testdata = {
141+
b"bytes_key": b"bytes_value",
142+
b"int_key": 42,
143+
b"list_key": [b"a", b"b", b"c", 1, 2, 3],
144+
b"dict_key": {b"nested": b"data", b"number": 999},
145+
}
146+
147+
148+
@pytest.mark.parametrize(
149+
"test_data, expected_out",
150+
[
151+
(testdata, testdata),
152+
({b"dict_key": {b"utf": "value"}}, {b"dict_key": {b"utf": b"value"}}),
153+
],
154+
)
155+
def test_bencode_roundtrip_consistency(test_data, expected_out):
156+
s = MockStorage(None, "nonexistent", None, create=True)
157+
158+
serialized1 = s._serialize(test_data)
159+
deserialized1 = s._deserialize(serialized1)
160+
161+
serialized2 = s._serialize(deserialized1)
162+
deserialized2 = s._deserialize(serialized2)
163+
164+
assert serialized1 == serialized2
165+
assert deserialized1 == deserialized2 == expected_out

0 commit comments

Comments
 (0)