vbase 1.0.0__tar.gz → 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. vbase-2.0.0/CHANGELOG.md +30 -0
  2. {vbase-1.0.0 → vbase-2.0.0}/MANIFEST.in +1 -0
  3. {vbase-1.0.0/vbase.egg-info → vbase-2.0.0}/PKG-INFO +18 -20
  4. {vbase-1.0.0 → vbase-2.0.0}/README.md +8 -9
  5. {vbase-1.0.0 → vbase-2.0.0}/pyproject.toml +1 -1
  6. vbase-2.0.0/requirements.in +8 -0
  7. {vbase-1.0.0 → vbase-2.0.0}/setup.py +0 -1
  8. {vbase-1.0.0 → vbase-2.0.0}/vbase/__init__.py +1 -3
  9. {vbase-1.0.0 → vbase-2.0.0}/vbase/_version.py +1 -1
  10. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/aggregate_indexing_service.py +1 -1
  11. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/commitment_service.py +13 -0
  12. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/failover_indexing_service.py +1 -1
  13. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/set_matching/__init__.py +1 -3
  14. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/set_matching/base_set_matching_service.py +1 -1
  15. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/set_matching/chain_set_matching_service.py +3 -2
  16. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/set_matching/fuzzy_set_matching_service.py +9 -7
  17. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/set_matching/head_based_set_matching_service.py +10 -7
  18. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/set_matching/types.py +4 -0
  19. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/sql_indexing_service.py +1 -1
  20. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/vbase_client.py +13 -0
  21. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/web3_commitment_service.py +33 -8
  22. {vbase-1.0.0 → vbase-2.0.0/vbase.egg-info}/PKG-INFO +18 -20
  23. {vbase-1.0.0 → vbase-2.0.0}/vbase.egg-info/SOURCES.txt +1 -0
  24. vbase-2.0.0/vbase.egg-info/requires.txt +8 -0
  25. vbase-1.0.0/requirements.in +0 -9
  26. vbase-1.0.0/vbase.egg-info/requires.txt +0 -9
  27. {vbase-1.0.0 → vbase-2.0.0}/LICENSE.txt +0 -0
  28. {vbase-1.0.0 → vbase-2.0.0}/NOTICE.txt +0 -0
  29. {vbase-1.0.0 → vbase-2.0.0}/setup.cfg +0 -0
  30. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/__init__.py +0 -0
  31. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/abi/CommitmentService.json +0 -0
  32. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/abi/CommitmentServiceTest.json +0 -0
  33. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/commitment_service_test.py +0 -0
  34. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/forwarder_commitment_service.py +0 -0
  35. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/forwarder_commitment_service_test.py +0 -0
  36. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/indexing_service.py +0 -0
  37. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/models.py +0 -0
  38. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/vbase_client_test.py +0 -0
  39. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/vbase_dataset.py +0 -0
  40. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/vbase_dataset_async.py +0 -0
  41. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/vbase_object.py +0 -0
  42. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/web3_http_commitment_service.py +0 -0
  43. {vbase-1.0.0 → vbase-2.0.0}/vbase/core/web3_http_commitment_service_test.py +0 -0
  44. {vbase-1.0.0 → vbase-2.0.0}/vbase/utils/__init__.py +0 -0
  45. {vbase-1.0.0 → vbase-2.0.0}/vbase/utils/crypto_utils.py +0 -0
  46. {vbase-1.0.0 → vbase-2.0.0}/vbase/utils/error_utils.py +0 -0
  47. {vbase-1.0.0 → vbase-2.0.0}/vbase/utils/log.py +0 -0
  48. {vbase-1.0.0 → vbase-2.0.0}/vbase.egg-info/dependency_links.txt +0 -0
  49. {vbase-1.0.0 → vbase-2.0.0}/vbase.egg-info/top_level.txt +0 -0
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ All notable changes are documented here, following
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ Earlier releases were not tracked in this file; see the
8
+ [commit history](https://github.com/validityBase/vbase-py/commits/main/)
9
+ for prior changes.
10
+
11
+ ## [Unreleased]
12
+
13
+ ## [2.0.0] - 2026-10-28
14
+
15
+ ### Changed
16
+
17
+ - Require Python 3.11 or later. Drop support for Python 3.8 through 3.10 (#84).
18
+ - Accept Web3 versions greater than or equal to 7.15 and less than 9 (#106).
19
+ - Set upper bounds for runtime dependencies (#63, #106).
20
+ - Remove the unused `imageio` runtime dependency (#110).
21
+
22
+ ### Fixed
23
+
24
+ - Use a matching `AddSet` receipt event to confirm a new set commitment.
25
+ Check the event's user and set CID. This avoids a false `add_set` failure
26
+ when an RPC backend returns stale state (#86).
27
+ - Retry the state check if a successful `add_set` transaction has no `AddSet`
28
+ receipt event. Fail if the set commitment cannot be confirmed after the
29
+ configured retries. Commitment confirmation does not guarantee immediate
30
+ visibility through an indexing service (#86).
@@ -1,3 +1,4 @@
1
1
  include README.md
2
2
  include requirements.in
3
3
  recursive-include vbase/core/abi *.json
4
+ include CHANGELOG.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vbase
3
- Version: 1.0.0
3
+ Version: 2.0.0
4
4
  Summary: vBase Python Software Development Kit (SDK)
5
5
  Author-email: vBase <tech@vbase.com>
6
6
  License-Expression: Apache-2.0
@@ -10,32 +10,31 @@ Project-URL: Issues, https://github.com/validityBase/vbase-py/issues
10
10
  Keywords: vbase,blockchain,provenance,web3,sdk
11
11
  Classifier: Operating System :: OS Independent
12
12
  Classifier: Programming Language :: Python :: 3
13
- Requires-Python: >=3.8
13
+ Requires-Python: >=3.11
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE.txt
16
16
  License-File: NOTICE.txt
17
- Requires-Dist: hexbytes>=0.3.1
18
- Requires-Dist: numpy>=1.24.0
19
- Requires-Dist: pandas>=2.0.0
20
- Requires-Dist: python-dotenv>=1.0.0
21
- Requires-Dist: requests>=2.31.0
22
- Requires-Dist: web3==7.15.0
23
- Requires-Dist: sqlmodel>=0.0.24
24
- Requires-Dist: imageio
25
- Requires-Dist: retry>=0.9.2
17
+ Requires-Dist: hexbytes<3,>=1.2.0
18
+ Requires-Dist: numpy<3,>=1.24.0
19
+ Requires-Dist: pandas<4,>=2.0.0
20
+ Requires-Dist: python-dotenv<2,>=1.0.0
21
+ Requires-Dist: requests<3,>=2.31.0
22
+ Requires-Dist: web3<9,>=7.15.0
23
+ Requires-Dist: sqlmodel<0.1,>=0.0.24
24
+ Requires-Dist: retry<1,>=0.9.2
26
25
  Dynamic: license-file
27
26
 
28
27
  # vbase-py
29
28
 
30
29
  vBase Python Software Development Kit (SDK)
31
30
 
32
- - Python 3.8+ support
31
+ - Python 3.11+ support
33
32
 
34
33
  ---
35
34
 
36
35
  ## License
37
36
 
38
- This project is licensed under the Apache 2.0 License - see the [LICENSE.txt](LICENSE.txt) file for details.
37
+ This project is licensed under the Apache 2.0 License - see the [LICENSE.txt](https://github.com/validityBase/vbase-py/blob/main/LICENSE.txt) file for details.
39
38
 
40
39
  ## Introduction
41
40
 
@@ -62,18 +61,17 @@ Install the package from PyPI:
62
61
  pip install vbase
63
62
  ```
64
63
 
65
- See the [local installation](https://docs.vbase.com/getting-started/python-quickstart/local-installation) and the [cloud notebooks](https://docs.vbase.com/getting-started/python-quickstart/cloud-notebooks) guides to get started using vBase from Python.
64
+ See the [local installation](https://docs.vbase.com/python-sdk/python-quickstart-readme/quickstart-1) and the [cloud notebooks](https://docs.vbase.com/python-sdk/python-quickstart-readme/quickstart) guides to get started using vBase from Python.
66
65
 
67
66
  ## Development
68
67
 
69
- Development and CI installs use generated requirements locks with pip
70
- hash-checking mode:
68
+ Install the generated development lock and package locally:
71
69
 
72
70
  ```bash
73
- python -m pip install --require-hashes -r requirements-dev.txt
71
+ python -m pip install --require-hashes -r requirements/dev.txt
74
72
  python -m pip install --no-deps --no-build-isolation -e .
75
73
  ```
76
74
 
77
- To update dependencies, edit the relevant `.in` file and regenerate the lock
78
- file with `pip-compile --generate-hashes`. See
79
- [internal/specs/python-dependency-hashes.md](internal/specs/python-dependency-hashes.md).
75
+ See `internal/specs/python-dependency-hashes.md` in this repository for the
76
+ dependency layout, lock policy, package metadata rules, and regeneration
77
+ commands.
@@ -2,13 +2,13 @@
2
2
 
3
3
  vBase Python Software Development Kit (SDK)
4
4
 
5
- - Python 3.8+ support
5
+ - Python 3.11+ support
6
6
 
7
7
  ---
8
8
 
9
9
  ## License
10
10
 
11
- This project is licensed under the Apache 2.0 License - see the [LICENSE.txt](LICENSE.txt) file for details.
11
+ This project is licensed under the Apache 2.0 License - see the [LICENSE.txt](https://github.com/validityBase/vbase-py/blob/main/LICENSE.txt) file for details.
12
12
 
13
13
  ## Introduction
14
14
 
@@ -35,18 +35,17 @@ Install the package from PyPI:
35
35
  pip install vbase
36
36
  ```
37
37
 
38
- See the [local installation](https://docs.vbase.com/getting-started/python-quickstart/local-installation) and the [cloud notebooks](https://docs.vbase.com/getting-started/python-quickstart/cloud-notebooks) guides to get started using vBase from Python.
38
+ See the [local installation](https://docs.vbase.com/python-sdk/python-quickstart-readme/quickstart-1) and the [cloud notebooks](https://docs.vbase.com/python-sdk/python-quickstart-readme/quickstart) guides to get started using vBase from Python.
39
39
 
40
40
  ## Development
41
41
 
42
- Development and CI installs use generated requirements locks with pip
43
- hash-checking mode:
42
+ Install the generated development lock and package locally:
44
43
 
45
44
  ```bash
46
- python -m pip install --require-hashes -r requirements-dev.txt
45
+ python -m pip install --require-hashes -r requirements/dev.txt
47
46
  python -m pip install --no-deps --no-build-isolation -e .
48
47
  ```
49
48
 
50
- To update dependencies, edit the relevant `.in` file and regenerate the lock
51
- file with `pip-compile --generate-hashes`. See
52
- [internal/specs/python-dependency-hashes.md](internal/specs/python-dependency-hashes.md).
49
+ See `internal/specs/python-dependency-hashes.md` in this repository for the
50
+ dependency layout, lock policy, package metadata rules, and regeneration
51
+ commands.
@@ -7,7 +7,7 @@ name = "vbase"
7
7
  dynamic = ["version", "dependencies"]
8
8
  description = "vBase Python Software Development Kit (SDK)"
9
9
  readme = "README.md"
10
- requires-python = ">=3.8"
10
+ requires-python = ">=3.11"
11
11
  license = "Apache-2.0"
12
12
  authors = [
13
13
  { name = "vBase", email = "tech@vbase.com" },
@@ -0,0 +1,8 @@
1
+ hexbytes>=1.2.0,<3
2
+ numpy>=1.24.0,<3
3
+ pandas>=2.0.0,<4
4
+ python-dotenv>=1.0.0,<2
5
+ requests>=2.31.0,<3
6
+ web3>=7.15.0,<9
7
+ sqlmodel>=0.0.24,<0.1
8
+ retry>=0.9.2,<1
@@ -2,5 +2,4 @@
2
2
 
3
3
  from setuptools import setup
4
4
 
5
-
6
5
  setup()
@@ -3,7 +3,6 @@
3
3
  A Python library for interacting with the validityBase (vBase) platform
4
4
  """
5
5
 
6
- from vbase._version import __version__
7
6
  from vbase.core.aggregate_indexing_service import AggregateIndexingService
8
7
  from vbase.core.failover_indexing_service import FailoverIndexingService
9
8
  from vbase.core.forwarder_commitment_service import ForwarderCommitmentService
@@ -41,6 +40,7 @@ from vbase.core.vbase_object import (
41
40
  from vbase.core.web3_http_commitment_service import Web3HTTPCommitmentService
42
41
  from vbase.core.web3_http_commitment_service_test import Web3HTTPCommitmentServiceTest
43
42
  from vbase.utils.log import get_default_logger
43
+ from ._version import __version__
44
44
 
45
45
  __all__ = [
46
46
  "__version__",
@@ -53,7 +53,6 @@ __all__ = [
53
53
  "IndexingService",
54
54
  "Web3HTTPIndexingService",
55
55
  "SQLIndexingService",
56
-
57
56
  "ChainSetMatchingService",
58
57
  "HeadBasedSetMatchingService",
59
58
  "FuzzySetMatchingService",
@@ -61,7 +60,6 @@ __all__ = [
61
60
  "SetMatch",
62
61
  "SetMatchingCriteria",
63
62
  "TimestampedCid",
64
-
65
63
  "FailoverIndexingService",
66
64
  "AggregateIndexingService",
67
65
  "VBaseObject",
@@ -1,3 +1,3 @@
1
1
  """Package version."""
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "2.0.0"
@@ -10,7 +10,7 @@ _LOG = get_default_logger(__name__)
10
10
  _LOG.setLevel(logging.INFO)
11
11
 
12
12
 
13
- class AggregateIndexingService(IndexingService):
13
+ class AggregateIndexingService(IndexingService): # pylint: disable=abstract-method
14
14
  """This indexing service aggregates the responses from a set of indexing services
15
15
 
16
16
  Each operation executes a corresponding method on all services and aggregates the results.
@@ -84,8 +84,21 @@ class CommitmentService(ABC):
84
84
  It does not specify how a hash is built and does not provide
85
85
  a schema for hashing complex information.
86
86
 
87
+ The operation is idempotent. A successful transaction receipt containing
88
+ a matching ``AddSet`` event is authoritative for the submitted write and
89
+ avoids a potentially stale state read. If an idempotent transaction emits
90
+ no event, the service confirms the existing commitment using bounded,
91
+ exponential-backoff retries.
92
+
93
+ Transaction confirmation does not guarantee immediate visibility through
94
+ an indexing service. Consumers that query indexing immediately after a
95
+ write may need read-your-write handling based on the returned transaction
96
+ hash.
97
+
87
98
  :param set_cid: The CID identifying the set.
88
99
  :return: The commitment log containing commitment receipt info.
100
+ :raises RuntimeError: If a matching event is absent and the commitment
101
+ cannot be confirmed after retrying.
89
102
  """
90
103
 
91
104
  @abstractmethod
@@ -9,7 +9,7 @@ _LOG = get_default_logger(__name__)
9
9
  _LOG.setLevel(logging.INFO)
10
10
 
11
11
 
12
- class FailoverIndexingService(IndexingService):
12
+ class FailoverIndexingService(IndexingService): # pylint: disable=abstract-method
13
13
  """This indexing service calls a set of indexing services one after another
14
14
  and provides a failover mechanism to ensure that if one service fails,
15
15
  another service can be used to retrieve the data.
@@ -3,10 +3,8 @@
3
3
  Core classes for set matching services in the validityBase (vBase) platform Python library
4
4
  """
5
5
 
6
- from vbase.core.set_matching.chain_set_matching_service import (
7
- ChainSetMatchingService,
8
- )
9
6
  from vbase.core.set_matching.base_set_matching_service import BaseSetMatchingService
7
+ from vbase.core.set_matching.chain_set_matching_service import ChainSetMatchingService
10
8
  from vbase.core.set_matching.fuzzy_set_matching_service import FuzzySetMatchingService
11
9
  from vbase.core.set_matching.head_based_set_matching_service import (
12
10
  HeadBasedSetMatchingService,
@@ -11,7 +11,7 @@ from vbase.core.models import EventAddSetObject, LastBatchProcessingTime
11
11
  from vbase.core.set_matching.types import SetIdentifier, SetMatch, SetMatchingCriteria
12
12
 
13
13
 
14
- class BaseSetMatchingService(ABC):
14
+ class BaseSetMatchingService(ABC): # pylint: disable=too-few-public-methods
15
15
  """
16
16
  Abstract base class for set matching strategies.
17
17
 
@@ -2,12 +2,13 @@
2
2
  Aggregate set matching strategies.
3
3
  """
4
4
 
5
-
6
5
  from vbase.core.set_matching.base_set_matching_service import BaseSetMatchingService
7
6
  from vbase.core.set_matching.types import SetMatch, SetMatchingCriteria
8
7
 
9
8
 
10
- class ChainSetMatchingService(BaseSetMatchingService):
9
+ class ChainSetMatchingService(
10
+ BaseSetMatchingService
11
+ ): # pylint: disable=too-few-public-methods
11
12
  """
12
13
  Aggregate multiple set matching strategies to return first non-empty result.
13
14
 
@@ -18,7 +18,9 @@ from vbase.core.set_matching.types import (
18
18
  )
19
19
 
20
20
 
21
- class FuzzySetMatchingService(BaseSetMatchingService):
21
+ class FuzzySetMatchingService(
22
+ BaseSetMatchingService
23
+ ): # pylint: disable=too-few-public-methods
22
24
  """
23
25
  Service for performing fuzzy set matching with tolerance.
24
26
  Finds sets whose elements match the criteria within a configurable tolerance.
@@ -142,7 +144,9 @@ class FuzzySetMatchingService(BaseSetMatchingService):
142
144
  rank=s.rank,
143
145
  set_cid=s.key.set_cid,
144
146
  user=s.key.user,
145
- last_matching_element_timestamp=s.objects[s.projected_last_element_index].timestamp,
147
+ last_matching_element_timestamp=s.objects[
148
+ s.projected_last_element_index
149
+ ].timestamp,
146
150
  data_freshness_timestamp=last_batch,
147
151
  is_full_match=(
148
152
  s.set_length == len(sorted_criteria.objects)
@@ -292,8 +296,8 @@ class FuzzySetMatchingService(BaseSetMatchingService):
292
296
  dp[i][j] = dp[i - 1][j - 1]
293
297
  else:
294
298
  dp[i][j] = 1 + min(
295
- dp[i - 1][j], # deletion
296
- dp[i][j - 1], # insertion
299
+ dp[i - 1][j], # deletion
300
+ dp[i][j - 1], # insertion
297
301
  dp[i - 1][j - 1], # substitution
298
302
  )
299
303
 
@@ -325,9 +329,7 @@ class FuzzySetMatchingService(BaseSetMatchingService):
325
329
  if not criteria.objects:
326
330
  return []
327
331
 
328
- required_matches = max(
329
- 1, math.ceil(len(criteria.objects) * (1.0 - tolerance))
330
- )
332
+ required_matches = max(1, math.ceil(len(criteria.objects) * (1.0 - tolerance)))
331
333
 
332
334
  # Collect all criteria CIDs
333
335
  criteria_cids = [obj.object_cid for obj in criteria.objects]
@@ -6,10 +6,17 @@ from sqlmodel import Session, create_engine, select
6
6
 
7
7
  from vbase.core.models import EventAddSetObject
8
8
  from vbase.core.set_matching.base_set_matching_service import BaseSetMatchingService
9
- from vbase.core.set_matching.types import ObjectSetData, SetIdentifier, SetMatch, SetMatchingCriteria
9
+ from vbase.core.set_matching.types import (
10
+ ObjectSetData,
11
+ SetIdentifier,
12
+ SetMatch,
13
+ SetMatchingCriteria,
14
+ )
10
15
 
11
16
 
12
- class HeadBasedSetMatchingService(BaseSetMatchingService):
17
+ class HeadBasedSetMatchingService(
18
+ BaseSetMatchingService
19
+ ): # pylint: disable=too-few-public-methods
13
20
  """
14
21
  Service for performing head-based set matching.
15
22
  Finds sets whose head (first elements) matches the elements specified in the criteria.
@@ -25,10 +32,7 @@ class HeadBasedSetMatchingService(BaseSetMatchingService):
25
32
  (distributed sets).
26
33
  """
27
34
 
28
- def __init__(
29
- self,
30
- db_url: str
31
- ):
35
+ def __init__(self, db_url: str):
32
36
  self.db_url = db_url
33
37
  self.db_engine = create_engine(db_url)
34
38
 
@@ -68,7 +72,6 @@ class HeadBasedSetMatchingService(BaseSetMatchingService):
68
72
  return []
69
73
  event_rows = self._load_candidate_events(session, candidate_keys)
70
74
 
71
-
72
75
  # Build ObjectSetData from event_rows (already ordered by timestamp)
73
76
  candidate_sets_dict: dict[SetIdentifier, ObjectSetData] = {}
74
77
  for event_row in event_rows:
@@ -5,6 +5,8 @@ Core types for indexing and matching strategies.
5
5
  from dataclasses import dataclass, field
6
6
 
7
7
  from vbase.core.models import EventAddSetObject
8
+
9
+
8
10
  @dataclass
9
11
  class TimestampedCid:
10
12
  """Pair of object_cid and its timestamp criteria."""
@@ -23,6 +25,7 @@ class SetMatchingCriteria:
23
25
 
24
26
  objects: list[TimestampedCid]
25
27
 
28
+
26
29
  @dataclass(frozen=True)
27
30
  class SetMatch:
28
31
  """
@@ -48,6 +51,7 @@ class SetIdentifier:
48
51
  Unique identifier for a set, based on its set_cid and user.
49
52
  Sets can span multiple chains (distributed sets).
50
53
  """
54
+
51
55
  set_cid: str
52
56
  user: str
53
57
 
@@ -19,7 +19,7 @@ from .models import (
19
19
  INDEXING_STALE_THRESHOLD_SECONDS = 60
20
20
 
21
21
 
22
- class SQLIndexingService(IndexingService):
22
+ class SQLIndexingService(IndexingService): # pylint: disable=abstract-method
23
23
  """
24
24
  Indexing service based on chain indexing data from sql db.
25
25
  """
@@ -106,8 +106,21 @@ class VBaseClient:
106
106
  It does not specify how a hash is built and does not provide
107
107
  a schema for hashing complex information.
108
108
 
109
+ The operation is idempotent. A successful transaction receipt containing
110
+ a matching ``AddSet`` event is authoritative for the submitted write and
111
+ avoids a potentially stale state read. If an idempotent transaction emits
112
+ no event, the service confirms the existing commitment using bounded,
113
+ exponential-backoff retries.
114
+
115
+ Transaction confirmation does not guarantee immediate visibility through
116
+ an indexing service. Consumers that query indexing immediately after a
117
+ write may need read-your-write handling based on the returned transaction
118
+ hash.
119
+
109
120
  :param set_cid: The CID (hash) identifying the set.
110
121
  :return: The commitment log containing commitment receipt info.
122
+ :raises RuntimeError: If a matching event is absent and the commitment
123
+ cannot be confirmed after retrying.
111
124
  """
112
125
  return self.commitment_service.add_set(set_cid)
113
126
 
@@ -14,6 +14,7 @@ from io import TextIOWrapper
14
14
  from typing import List, Optional, Type, Union
15
15
 
16
16
  import pandas as pd
17
+ from retry.api import retry_call
17
18
  from web3 import Web3
18
19
  from web3.contract import Contract
19
20
  from web3.contract.base_contract import EventLogErrorFlags
@@ -32,6 +33,10 @@ class Web3CommitmentService(CommitmentService, ABC):
32
33
  either directly or via a forwarder.
33
34
  """
34
35
 
36
+ RETRY_TRIES = 3
37
+ RETRY_DELAY = 1
38
+ RETRY_BACKOFF = 2
39
+
35
40
  def __init__(
36
41
  self, w3: Web3, commitment_service_contract: Union[Type[Contract], Contract]
37
42
  ):
@@ -113,6 +118,24 @@ class Web3CommitmentService(CommitmentService, ABC):
113
118
  _LOG.error(msg)
114
119
  raise RuntimeError(msg)
115
120
 
121
+ def _require_user_set_exists(self, user: str, set_cid: str) -> None:
122
+ """Raise if a set commitment is not visible for a user."""
123
+ if not self.user_set_exists(user, set_cid):
124
+ raise RuntimeError(
125
+ "AddSet event not found and set commitment does not exist"
126
+ )
127
+
128
+ def _user_set_exists_with_retry(self, user: str, set_cid: str) -> None:
129
+ """Confirm set visibility with bounded exponential-backoff retries."""
130
+ retry_call(
131
+ self._require_user_set_exists,
132
+ fargs=[user, set_cid],
133
+ tries=self.RETRY_TRIES,
134
+ delay=self.RETRY_DELAY,
135
+ backoff=self.RETRY_BACKOFF,
136
+ logger=_LOG,
137
+ )
138
+
116
139
  def _add_set_worker(self, set_cid: str, receipt: TxReceipt) -> dict:
117
140
  """Process results of a addSect transaction.
118
141
 
@@ -132,6 +155,12 @@ class Web3CommitmentService(CommitmentService, ABC):
132
155
  cl = dict(add_set_events[0]["args"])
133
156
  # Convert bytestrings to strings to allow serialization for upper layers.
134
157
  cl["setCid"] = bytes_to_hex_str(cl["setCid"])
158
+ if str(cl["user"]).lower() != self.get_default_user().lower():
159
+ raise RuntimeError("AddSet event user does not match requested user")
160
+ if cl["setCid"].lower() != set_cid.lower():
161
+ raise RuntimeError(
162
+ "AddSet event set CID does not match requested set CID"
163
+ )
135
164
  cl["transactionHash"] = receipt["transactionHash"]
136
165
  # Expose committer as userAddress for API consumers.
137
166
  self._init_receipt_fields(cl)
@@ -147,14 +176,10 @@ class Web3CommitmentService(CommitmentService, ABC):
147
176
  else:
148
177
  # No event means addSet was a no-op (set already existed).
149
178
  cl = {}
150
-
151
- # Confirm that the set exists following the completed commitment.
152
- # This is useful for catching any transaction failures
153
- # or errors in the node infrastructure to report failures properly.
154
- # Note that this may be a forwarded transaction.
155
- # In this case, the receipt["from"] is the forwarder/relayer address
156
- # and cl["user"] is the user address for the commitment.
157
- assert self.user_set_exists(self.get_default_user(), set_cid)
179
+ # Confirm that an eventless transaction was the expected idempotent no-op.
180
+ # A matching AddSet event is already authoritative proof of a new
181
+ # commitment and avoids a stale read from a different RPC backend.
182
+ self._user_set_exists_with_retry(self.get_default_user(), set_cid)
158
183
 
159
184
  _LOG.debug("Commitment log:\n%s", pprint.pformat(cl))
160
185
  return cl
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vbase
3
- Version: 1.0.0
3
+ Version: 2.0.0
4
4
  Summary: vBase Python Software Development Kit (SDK)
5
5
  Author-email: vBase <tech@vbase.com>
6
6
  License-Expression: Apache-2.0
@@ -10,32 +10,31 @@ Project-URL: Issues, https://github.com/validityBase/vbase-py/issues
10
10
  Keywords: vbase,blockchain,provenance,web3,sdk
11
11
  Classifier: Operating System :: OS Independent
12
12
  Classifier: Programming Language :: Python :: 3
13
- Requires-Python: >=3.8
13
+ Requires-Python: >=3.11
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE.txt
16
16
  License-File: NOTICE.txt
17
- Requires-Dist: hexbytes>=0.3.1
18
- Requires-Dist: numpy>=1.24.0
19
- Requires-Dist: pandas>=2.0.0
20
- Requires-Dist: python-dotenv>=1.0.0
21
- Requires-Dist: requests>=2.31.0
22
- Requires-Dist: web3==7.15.0
23
- Requires-Dist: sqlmodel>=0.0.24
24
- Requires-Dist: imageio
25
- Requires-Dist: retry>=0.9.2
17
+ Requires-Dist: hexbytes<3,>=1.2.0
18
+ Requires-Dist: numpy<3,>=1.24.0
19
+ Requires-Dist: pandas<4,>=2.0.0
20
+ Requires-Dist: python-dotenv<2,>=1.0.0
21
+ Requires-Dist: requests<3,>=2.31.0
22
+ Requires-Dist: web3<9,>=7.15.0
23
+ Requires-Dist: sqlmodel<0.1,>=0.0.24
24
+ Requires-Dist: retry<1,>=0.9.2
26
25
  Dynamic: license-file
27
26
 
28
27
  # vbase-py
29
28
 
30
29
  vBase Python Software Development Kit (SDK)
31
30
 
32
- - Python 3.8+ support
31
+ - Python 3.11+ support
33
32
 
34
33
  ---
35
34
 
36
35
  ## License
37
36
 
38
- This project is licensed under the Apache 2.0 License - see the [LICENSE.txt](LICENSE.txt) file for details.
37
+ This project is licensed under the Apache 2.0 License - see the [LICENSE.txt](https://github.com/validityBase/vbase-py/blob/main/LICENSE.txt) file for details.
39
38
 
40
39
  ## Introduction
41
40
 
@@ -62,18 +61,17 @@ Install the package from PyPI:
62
61
  pip install vbase
63
62
  ```
64
63
 
65
- See the [local installation](https://docs.vbase.com/getting-started/python-quickstart/local-installation) and the [cloud notebooks](https://docs.vbase.com/getting-started/python-quickstart/cloud-notebooks) guides to get started using vBase from Python.
64
+ See the [local installation](https://docs.vbase.com/python-sdk/python-quickstart-readme/quickstart-1) and the [cloud notebooks](https://docs.vbase.com/python-sdk/python-quickstart-readme/quickstart) guides to get started using vBase from Python.
66
65
 
67
66
  ## Development
68
67
 
69
- Development and CI installs use generated requirements locks with pip
70
- hash-checking mode:
68
+ Install the generated development lock and package locally:
71
69
 
72
70
  ```bash
73
- python -m pip install --require-hashes -r requirements-dev.txt
71
+ python -m pip install --require-hashes -r requirements/dev.txt
74
72
  python -m pip install --no-deps --no-build-isolation -e .
75
73
  ```
76
74
 
77
- To update dependencies, edit the relevant `.in` file and regenerate the lock
78
- file with `pip-compile --generate-hashes`. See
79
- [internal/specs/python-dependency-hashes.md](internal/specs/python-dependency-hashes.md).
75
+ See `internal/specs/python-dependency-hashes.md` in this repository for the
76
+ dependency layout, lock policy, package metadata rules, and regeneration
77
+ commands.
@@ -1,3 +1,4 @@
1
+ CHANGELOG.md
1
2
  LICENSE.txt
2
3
  MANIFEST.in
3
4
  NOTICE.txt
@@ -0,0 +1,8 @@
1
+ hexbytes<3,>=1.2.0
2
+ numpy<3,>=1.24.0
3
+ pandas<4,>=2.0.0
4
+ python-dotenv<2,>=1.0.0
5
+ requests<3,>=2.31.0
6
+ web3<9,>=7.15.0
7
+ sqlmodel<0.1,>=0.0.24
8
+ retry<1,>=0.9.2
@@ -1,9 +0,0 @@
1
- hexbytes>=0.3.1
2
- numpy>=1.24.0
3
- pandas>=2.0.0
4
- python-dotenv>=1.0.0
5
- requests>=2.31.0
6
- web3==7.15.0
7
- sqlmodel>=0.0.24
8
- imageio
9
- retry>=0.9.2
@@ -1,9 +0,0 @@
1
- hexbytes>=0.3.1
2
- numpy>=1.24.0
3
- pandas>=2.0.0
4
- python-dotenv>=1.0.0
5
- requests>=2.31.0
6
- web3==7.15.0
7
- sqlmodel>=0.0.24
8
- imageio
9
- retry>=0.9.2
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes