Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
dd1e404
Merge branch 'release' into master
jansegre Dec 4, 2025
7143497
fix(nano): runtime type restriction for `emit_event` syscall
jansegre Dec 5, 2025
3971b59
Merge pull request #1506 from HathorNetwork/fix/nano/type-check-emit-…
jansegre Dec 8, 2025
15bad95
fix(nano): state API regression when requesting dict fields
jansegre Dec 8, 2025
ab8add7
Merge pull request #1507 from HathorNetwork/fix/nano/state-api-contai…
jansegre Dec 8, 2025
725857d
Merge branch 'release' into master
jansegre Dec 9, 2025
f8d2c4f
chore: rename blueprint class to avoid pytest warning
jansegre Dec 10, 2025
d9bd072
Merge pull request #1510 from HathorNetwork/chore/fix-test-warning
jansegre Dec 10, 2025
623856d
feat(nano): Forbid negative balance during execution
msbrogli Dec 9, 2025
5e3d848
feat(consensus): eliminate block ties
msbrogli Jun 16, 2023
0f8cb8d
feat(indexes): remove sync-v1 indexes
jansegre Jan 8, 2025
a579e7f
Merge pull request #1200 from HathorNetwork/feat/remove-sync-v1-indexes
jansegre Dec 11, 2025
e6d5726
Merge branch 'release' into master
jansegre Dec 12, 2025
74f869a
fix(indexes): iterating all mempool transactions could visit every block
jansegre Dec 16, 2025
6a124f4
Merge pull request #1519 from HathorNetwork/fix/iter-mempool-runoff
jansegre Dec 18, 2025
2497e29
fix(sync): do not count voided blocks towards repeated blocks limit
jansegre Dec 17, 2025
e3bba0d
Merge pull request #1520 from HathorNetwork/fix/prevent-repeated-bloc…
jansegre Dec 18, 2025
b680d42
tests: fix flaky
glevco Jan 6, 2026
c75c2b0
Merge pull request #1539 from HathorNetwork/tests/fix-flaky
jansegre Jan 6, 2026
b54dfe5
chore(ci): update macos (#1474)
glevco Jan 6, 2026
ec30175
fix: nc-fail should not count for excluding conflicts from mempool
jansegre Dec 20, 2025
44a8bb4
Merge pull request #1532 from HathorNetwork/fix/conflict-with-executi…
jansegre Jan 6, 2026
852c45b
Feat(dynamic-transaction-model): fee based tokens feature activation …
raul-oliveira Jan 7, 2026
681a4ef
feat: move hathorlib to hathor-core (#1533)
r4mmer Jan 7, 2026
529ffce
chore(ci): update hathorlib ci (#1540)
glevco Jan 7, 2026
35b3614
fix: Add hathorlib to Dockerfile (#1545)
luislhl Jan 8, 2026
cafc16b
feat(mempool): Optimize mempool cleaning
msbrogli Dec 20, 2025
ab33438
refactor(traversal): make neighbors traversal explicitly required (#1…
glevco Jan 8, 2026
6b4b647
chore: update typing deps (#1541)
glevco Jan 8, 2026
d86623d
refactor: fix asyncioreactor `get_running_loop` warning
jansegre Dec 11, 2025
ab15cc2
refactor(utils): replace deprecated cgi module
jansegre Sep 17, 2025
ee84245
refactor: fix datetime.datetime.utcnow deprecation warning
jansegre Dec 11, 2025
3ab1510
Merge pull request #1529 from HathorNetwork/refactor/fix-several-warn…
jansegre Jan 12, 2026
9d5c735
refactor(verification): clarify postponed verification (#1546)
glevco Jan 12, 2026
a1cd749
fix(nano): Fix NCBlockSorter O(n) operation
msbrogli Dec 29, 2025
cf5fc97
Merge branch 'release' into master
jansegre Jan 13, 2026
b164a87
feat(events): add vertex name to events (#1558)
glevco Jan 19, 2026
932ce5f
refactor: improve loading logs (#1549)
glevco Jan 20, 2026
42aa09a
refactor(storage): merge cache storage and rocksdb storage (#1542)
glevco Jan 20, 2026
33f0697
refactor(storage): make indexes non-nullable (#1543)
glevco Jan 20, 2026
ee6098f
chore: fee feature activation on testnet-india
jansegre Jan 20, 2026
c78c142
Merge pull request #1548 from HathorNetwork/raul-oliveira/fee-feature…
jansegre Jan 20, 2026
dae8929
feat(dag-builder): add step fn (#1555)
glevco Jan 21, 2026
e8640de
fix: add missing callback res after refactor (#1560)
glevco Jan 21, 2026
630aa4e
feat(nc-history-order): Add order param to NCHistoryResource (#1528)
jackal-thothid Jan 21, 2026
e41770e
Merge pull request #1553 from HathorNetwork/master
jansegre Jan 21, 2026
11f318d
feat(indexes): prevent full node crash on non-critical indexes errors…
glevco Jan 21, 2026
1d20643
fix(nano): CallerId name on Blueprint info API (#1567)
glevco Jan 22, 2026
a010288
feat: add support for Python 3.13 (#1538)
glevco Jan 22, 2026
ac49315
refactor: feature activation handling (#1568)
glevco Jan 24, 2026
73d3e56
refactor(consensus): feature activation mempool rules
glevco Jan 24, 2026
be480c9
Merge pull request #1569 from HathorNetwork/refactor/consensus-features
jansegre Jan 26, 2026
ccfe8c6
refactor(nano): Move the nano execution logic to a separate file
msbrogli Jan 23, 2026
b150e70
feat(nano): add support for json_dumps (#1572)
glevco Jan 27, 2026
02d339f
refactor(nano): Refactor to facilitate dry runnning blocks and transa…
msbrogli Jan 23, 2026
6ef1f93
test: Fix flaky tests
msbrogli Jan 27, 2026
a5c6ab2
feat(script): deprecate unnecessary opcodes
glevco Jan 26, 2026
90702bc
refactor(nano): Remove dead reorg cleanup code from block executor
msbrogli Jan 24, 2026
7974ca5
refactor: wallet on_new_tx (#1561)
glevco Jan 28, 2026
e9b49b0
chore: configure feature activations for v0.69.0 release
jansegre Jan 27, 2026
1ddc828
Merge pull request #1579 from HathorNetwork/master
jansegre Jan 30, 2026
c50cebd
chore: adjust testnet config for v0.69.0 release
jansegre Feb 3, 2026
87c8593
Merge pull request #1591 from HathorNetwork/hotfix
jansegre Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/actions/setup-hathor-env/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ runs:
run: |
brew cleanup -q
# brew update -q
brew install -q graphviz rocksdb pkg-config
brew install -q graphviz rocksdb pkg-config openssl
echo "PYCOIN_LIBCRYPTO_PATH=$(brew --prefix openssl)/lib/libcrypto.dylib" >> $GITHUB_ENV
shell: bash

- name: Install Poetry dependencies
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/lib.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# yamllint disable rule:line-length
name: lib_tests
on: # yamllint disable-line rule:truthy
push:
branches:
- master
- dev
tags:
- v*
pull_request:
branches:
- master
- dev
jobs:
test:
name: python-${{ matrix.python }} (${{ matrix.os }})
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: ./hathorlib
timeout-minutes: 40 # default is 360
strategy:
matrix:
python:
- "3.11"
- "3.12"
os:
- ubuntu-22.04
- macos-15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install Poetry
run: pip install 'poetry<2'
- name: Install Poetry dependencies
run: poetry install -n --no-root -E client
- name: Run linters
run: poetry run make check
- name: Run tests
run: poetry run make tests
continue-on-error: ${{ matrix.tier > 1 }}
- name: Upload coverage
uses: codecov/codecov-action@29386c70ef20e286228c72b668a06fd0e8399192 # https://github.com/codecov/codecov-action/releases/tag/v1
if: matrix.python == 3.11 && startsWith(matrix.os, 'ubuntu')
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ jobs:
import os
import json
full_matrix = {
'python': ['3.11', '3.12'],
'python': ['3.11', '3.12', '3.13'],
# available OS's: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on
'os': ['ubuntu-22.04', 'macos-13'],
'os': ['ubuntu-22.04', 'macos-15'],
}
# this is the fastest one:
reduced_matrix = {
Expand Down
3 changes: 3 additions & 0 deletions .yamllint.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
extends: default

ignore:
- .venv/

rules:
document-start: disable
line-length:
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ RUN pip --no-input --no-cache-dir install --upgrade pip wheel poetry
ENV POETRY_VIRTUALENVS_IN_PROJECT=true
WORKDIR /app/
COPY pyproject.toml poetry.lock ./
COPY hathorlib ./hathorlib
RUN poetry install -n -E sentry --no-root --only=main
COPY hathor ./hathor
COPY hathor_cli ./hathor_cli
Expand Down
2 changes: 1 addition & 1 deletion extras/github/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def extract_pyver(filename):
output['tags'] = 'dont-push--local-only'
output['push'] = 'false'

output['created'] = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
output['created'] = datetime.datetime.now(datetime.UTC).strftime('%Y-%m-%dT%H:%M:%SZ')
output['dockerfile'] = dockerfile

return output
Expand Down
3 changes: 2 additions & 1 deletion hathor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
TxOutputScript,
VertexId,
)
from hathor.nanocontracts.utils import sha3, verify_ecdsa
from hathor.nanocontracts.utils import json_dumps, sha3, verify_ecdsa
from hathor.version import __version__

__all__ = [
Expand Down Expand Up @@ -73,5 +73,6 @@
'VertexId',
'sha3',
'verify_ecdsa',
'json_dumps',
'__version__',
]
2 changes: 1 addition & 1 deletion hathor/_openapi/openapi_base.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
],
"info": {
"title": "Hathor API",
"version": "0.68.4"
"version": "0.69.0"
},
"consumes": [
"application/json"
Expand Down
2 changes: 1 addition & 1 deletion hathor/api_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def get_arg_default(args: dict[bytes, list[bytes]], key: str, default: T) -> T:
bkey = key.encode()
values = args.get(bkey)
if not values:
return cast(T, default)
return default
value: bytes = values[0]
if isinstance(default, int):
return cast(T, int(value))
Expand Down
41 changes: 14 additions & 27 deletions hathor/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
from hathor.storage import RocksDBStorage
from hathor.stratum import StratumFactory
from hathor.transaction.json_serializer import VertexJsonSerializer
from hathor.transaction.storage import TransactionCacheStorage, TransactionRocksDBStorage, TransactionStorage
from hathor.transaction.storage import TransactionRocksDBStorage, TransactionStorage
from hathor.transaction.storage.rocksdb_storage import CacheConfig
from hathor.transaction.vertex_children import RocksDBVertexChildrenService
from hathor.transaction.vertex_parser import VertexParser
from hathor.util import Random, get_environment_info
Expand Down Expand Up @@ -102,7 +103,7 @@ class BuildArtifacts(NamedTuple):
tx_storage: TransactionStorage
feature_service: FeatureService
bit_signaling_service: BitSignalingService
indexes: Optional[IndexesManager]
indexes: IndexesManager
wallet: Optional[BaseWallet]
rocksdb_storage: RocksDBStorage
stratum_factory: Optional[StratumFactory]
Expand Down Expand Up @@ -410,18 +411,17 @@ def _get_or_create_nc_log_storage(self) -> NCLogStorage:
def _get_or_create_consensus(self) -> ConsensusAlgorithm:
if self._consensus is None:
soft_voided_tx_ids = self._get_soft_voided_tx_ids()
pubsub = self._get_or_create_pubsub()
nc_storage_factory = self._get_or_create_nc_storage_factory()
nc_calls_sorter = self._get_nc_calls_sorter()
self._consensus = ConsensusAlgorithm(
nc_storage_factory=nc_storage_factory,
soft_voided_tx_ids=soft_voided_tx_ids,
pubsub=pubsub,
settings=self._get_or_create_settings(),
runner_factory=self._get_or_create_runner_factory(),
nc_log_storage=self._get_or_create_nc_log_storage(),
nc_calls_sorter=nc_calls_sorter,
feature_service=self._get_or_create_feature_service(),
tx_storage=self._get_or_create_tx_storage(),
)

return self._consensus
Expand Down Expand Up @@ -506,38 +506,27 @@ def _get_or_create_tx_storage(self) -> TransactionStorage:
self._tx_storage.indexes = indexes
return self._tx_storage

store_indexes: Optional[IndexesManager] = indexes
cache_config: CacheConfig | None = None
if self._tx_storage_cache:
store_indexes = None
cache_config = CacheConfig()
if self._tx_storage_cache_capacity is not None:
cache_config.capacity = self._tx_storage_cache_capacity

rocksdb_storage = self._get_or_create_rocksdb_storage()
nc_storage_factory = self._get_or_create_nc_storage_factory()
vertex_parser = self._get_or_create_vertex_parser()
vertex_children_service = RocksDBVertexChildrenService(rocksdb_storage)
self._tx_storage = TransactionRocksDBStorage(
rocksdb_storage,
indexes=store_indexes,
reactor=self._get_reactor(),
rocksdb_storage=rocksdb_storage,
indexes=indexes,
settings=settings,
vertex_parser=vertex_parser,
nc_storage_factory=nc_storage_factory,
vertex_children_service=vertex_children_service,
cache_config=cache_config,
)

if self._tx_storage_cache:
reactor = self._get_reactor()
kwargs: dict[str, Any] = {}
if self._tx_storage_cache_capacity is not None:
kwargs['capacity'] = self._tx_storage_cache_capacity
self._tx_storage = TransactionCacheStorage(
self._tx_storage,
reactor,
indexes=indexes,
settings=settings,
nc_storage_factory=nc_storage_factory,
vertex_children_service=vertex_children_service,
**kwargs
)

return self._tx_storage

def _get_or_create_event_storage(self) -> EventStorage:
Expand Down Expand Up @@ -666,7 +655,6 @@ def _get_or_create_vertex_handler(self) -> VertexHandler:
feature_service=self._get_or_create_feature_service(),
execution_manager=self._get_or_create_execution_manager(),
pubsub=self._get_or_create_pubsub(),
wallet=self._get_or_create_wallet(),
)

return self._vertex_handler
Expand Down Expand Up @@ -794,9 +782,8 @@ def enable_event_queue(self) -> 'Builder':
def set_tx_storage(self, tx_storage: TransactionStorage) -> 'Builder':
self.check_if_can_modify()
self._tx_storage = tx_storage
internal = tx_storage.store if isinstance(tx_storage, TransactionCacheStorage) else tx_storage
assert isinstance(internal, TransactionRocksDBStorage)
self._rocksdb_storage = internal._rocksdb_storage
assert isinstance(tx_storage, TransactionRocksDBStorage)
self._rocksdb_storage = tx_storage._rocksdb_storage
return self

def set_event_storage(self, event_storage: EventStorage) -> 'Builder':
Expand Down
1 change: 0 additions & 1 deletion hathor/builder/resources_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,6 @@ def create_resources(self) -> server.Site:
parent.putChild(url_path, resource)

# Websocket resource
assert self.manager.tx_storage.indexes is not None
ws_factory = HathorAdminWebsocketFactory(manager=self.manager,
metrics=self.manager.metrics,
address_index=self.manager.tx_storage.indexes.addresses)
Expand Down
25 changes: 23 additions & 2 deletions hathor/conf/mainnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

from hathor.checkpoint import Checkpoint as cp
from hathor.conf.settings import HathorSettings, NanoContractsSetting
from hathor.conf.settings import FeatureSetting, HathorSettings
from hathor.feature_activation.feature import Feature
from hathor.feature_activation.model.criteria import Criteria
from hathor.feature_activation.settings import Settings as FeatureActivationSettings
Expand Down Expand Up @@ -213,7 +213,8 @@
'00004305882eb3eef6b45f025ff58eb7baa5ca35f7d6f42c8b085482b00474e6',
'000045ecbab77c9a8d819ff6d26893b9da2774eee5539f17d8fc2394f82b758e',
])),
ENABLE_NANO_CONTRACTS=NanoContractsSetting.FEATURE_ACTIVATION,
ENABLE_NANO_CONTRACTS=FeatureSetting.FEATURE_ACTIVATION,
ENABLE_FEE_BASED_TOKENS=FeatureSetting.DISABLED,
NC_ON_CHAIN_BLUEPRINT_ALLOWED_ADDRESSES=[
'HDkKGHwDHTuUGbhET73XdTJZkS8uU7PHf9',
'HUbxYhtqW8pdRCC2WngPxN7MB4SUMDPrrh',
Expand Down Expand Up @@ -256,6 +257,26 @@
version='0.67.0',
signal_support_by_default=True,
),
Feature.FEE_TOKENS: Criteria(
# XXX: parity with hathor/conf/mainnet.yml
bit=2,
start_height=6_249_600,
timeout_height=6_592_320,
minimum_activation_height=6_350_400,
lock_in_on_timeout=False,
version='0.69.0',
signal_support_by_default=True,
),
Feature.OPCODES_V2: Criteria(
# XXX: parity with hathor/conf/mainnet.yml
bit=3,
start_height=6_249_600,
timeout_height=6_592_320,
minimum_activation_height=6_350_400,
lock_in_on_timeout=False,
version='0.69.0',
signal_support_by_default=True,
),
}
)
)
20 changes: 20 additions & 0 deletions hathor/conf/mainnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,26 @@ FEATURE_ACTIVATION:
version: 0.67.0
signal_support_by_default: true

FEE_TOKENS:
bit: 2
# Right now the best block is 6_248_703 at Tuesday, 2026-01-27 22:45:36 GMT
start_height: 6_249_600 # expected around 2026-02-04 06:14:06 GMT
timeout_height: 6_592_320 # 16 weeks, expected around 2026-05-27 06:14:06 GMT
minimum_activation_height: 6_350_400 # 4 weeks, expected around 2026-03-04 06:14:06 GMT
lock_in_on_timeout: false
version: 0.69.0
signal_support_by_default: true

OPCODES_V2:
bit: 3
# Right now the best block is 6_248_703 at Tuesday, 2026-01-27 21:45:36 GMT
start_height: 6_249_600 # expected around 2026-02-04 06:14:06 GMT
timeout_height: 6_592_320 # 16 weeks, expected around 2026-05-27 06:14:06 GMT
minimum_activation_height: 6_350_400 # 4 weeks, expected around 2026-03-04 06:14:06 GMT
lock_in_on_timeout: false
version: 0.69.0
signal_support_by_default: true

ENABLE_NANO_CONTRACTS: feature_activation
NC_ON_CHAIN_BLUEPRINT_ALLOWED_ADDRESSES:
- HDkKGHwDHTuUGbhET73XdTJZkS8uU7PHf9
Expand Down
20 changes: 13 additions & 7 deletions hathor/conf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@


@unique
class NanoContractsSetting(StrEnum):
"""Enum to configure the state of the Nano Contracts feature."""
class FeatureSetting(StrEnum):
"""Enum to configure the state of a feature."""

# Completely disabled.
DISABLED = auto()
Expand All @@ -49,14 +49,14 @@ class NanoContractsSetting(StrEnum):

def __bool__(self) -> bool:
"""
>>> bool(NanoContractsSetting.DISABLED)
>>> bool(FeatureSetting.DISABLED)
False
>>> bool(NanoContractsSetting.ENABLED)
>>> bool(FeatureSetting.ENABLED)
True
>>> bool(NanoContractsSetting.FEATURE_ACTIVATION)
>>> bool(FeatureSetting.FEATURE_ACTIVATION)
True
"""
return self in (NanoContractsSetting.ENABLED, NanoContractsSetting.FEATURE_ACTIVATION)
return self in (FeatureSetting.ENABLED, FeatureSetting.FEATURE_ACTIVATION)


class HathorSettings(NamedTuple):
Expand Down Expand Up @@ -480,7 +480,13 @@ def GENESIS_TX2_TIMESTAMP(self) -> int:
MAX_UNVERIFIED_PEERS_PER_CONN: int = 100

# Used to enable nano contracts.
ENABLE_NANO_CONTRACTS: NanoContractsSetting = NanoContractsSetting.DISABLED
ENABLE_NANO_CONTRACTS: FeatureSetting = FeatureSetting.DISABLED

# Used to enable fee-based tokens.
ENABLE_FEE_BASED_TOKENS: FeatureSetting = FeatureSetting.DISABLED

# Used to enable opcodes V2.
ENABLE_OPCODES_V2: FeatureSetting = FeatureSetting.DISABLED

# List of enabled blueprints.
BLUEPRINTS: dict[bytes, str] = {}
Expand Down
Loading