From 08cd6263c847a11bbd0f4b0f2ebade8eff77442a Mon Sep 17 00:00:00 2001 From: liustve Date: Tue, 28 Jan 2025 19:54:30 +0000 Subject: [PATCH 1/4] lineage supprt for aws xray propagator --- .../propagators/aws/aws_xray_propagator.py | 101 +++++++++-- .../tests/test_aws_xray_propagator.py | 167 ++++++++++++++++-- 2 files changed, 240 insertions(+), 28 deletions(-) diff --git a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py index d9b99f35ca..e9a456451f 100644 --- a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py +++ b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py @@ -60,7 +60,7 @@ import typing from os import environ -from opentelemetry import trace +from opentelemetry import baggage, trace from opentelemetry.context import Context from opentelemetry.propagators.textmap import ( CarrierT, @@ -92,6 +92,16 @@ IS_SAMPLED = "1" NOT_SAMPLED = "0" +LINEAGE_KEY = "Lineage" +LINEAGE_DELIMITER = ":" +LINEAGE_MAX_LENGTH = 18 +LINEAGE_MIN_LENGTH = 12 +LINEAGE_HASH_LENGTH = 8 +LINEAGE_MAX_LOOP_COUNTER = 32767 +LINEAGE_MAX_REQUEST_COUNTER = 255 +LINEAGE_MIN_LOOP_REQUEST_COUNTER = 0 +INVALID_LINEAGE_HEADER = "-1:11111111:0" + _logger = logging.getLogger(__name__) @@ -131,11 +141,9 @@ def extract( return context try: - ( - trace_id, - span_id, - sampled, - ) = AwsXRayPropagator._extract_span_properties(trace_header) + (trace_id, span_id, sampled, lineage) = ( + AwsXRayPropagator._extract_span_properties(trace_header) + ) except AwsParseTraceHeaderError as err: _logger.debug(err.message) return context @@ -158,6 +166,9 @@ def extract( ) return context + if lineage is not INVALID_LINEAGE_HEADER: + context.update(baggage.set_baggage(LINEAGE_KEY, lineage, context=context)) + return trace.set_span_in_context( trace.NonRecordingSpan(span_context), context=context ) @@ -167,6 +178,7 @@ def _extract_span_properties(trace_header): trace_id = trace.INVALID_TRACE_ID span_id = trace.INVALID_SPAN_ID sampled = False + lineage = INVALID_LINEAGE_HEADER for kv_pair_str in trace_header.split(KV_PAIR_DELIMITER): try: @@ -231,7 +243,18 @@ def _extract_span_properties(trace_header): sampled = AwsXRayPropagator._parse_sampled_flag(value) - return trace_id, span_id, sampled + elif key == LINEAGE_KEY: + lineage = AwsXRayPropagator._parse_lineage_header(value) + if not AwsXRayPropagator._is_valid_lineage(lineage): + _logger.debug( + "Invalid Lineage in X-Ray trace header: '%s' with value '%s'. Returning trace header with no lineage", + TRACE_HEADER_KEY, + lineage, + ) + + lineage = INVALID_LINEAGE_HEADER + + return trace_id, span_id, sampled, lineage @staticmethod def _validate_trace_id(trace_id_str): @@ -262,9 +285,7 @@ def _parse_span_id(span_id_str): @staticmethod def _validate_sampled_flag(sampled_flag_str): - return len( - sampled_flag_str - ) == SAMPLED_FLAG_LENGTH and sampled_flag_str in ( + return len(sampled_flag_str) == SAMPLED_FLAG_LENGTH and sampled_flag_str in ( IS_SAMPLED, NOT_SAMPLED, ) @@ -273,6 +294,54 @@ def _validate_sampled_flag(sampled_flag_str): def _parse_sampled_flag(sampled_flag_str): return sampled_flag_str[0] == IS_SAMPLED + @staticmethod + def _parse_lineage_header(xray_lineage_header): + num_of_delimiters = xray_lineage_header.count(LINEAGE_DELIMITER) + + if ( + len(xray_lineage_header) < LINEAGE_MIN_LENGTH + or len(xray_lineage_header) > LINEAGE_MAX_LENGTH + or num_of_delimiters != 2 + ): + return INVALID_LINEAGE_HEADER + + return xray_lineage_header + + @staticmethod + def _is_valid_lineage(key): + split = key.split(LINEAGE_DELIMITER) + lineage_hash = split[1] + loop_counter = AwsXRayPropagator._parse_natural_or_return_negative(split[0], 10) + request_counter = AwsXRayPropagator._parse_natural_or_return_negative( + split[2], 10 + ) + + is_hash_valid = ( + len(lineage_hash) == LINEAGE_HASH_LENGTH + and AwsXRayPropagator._parse_natural_or_return_negative(lineage_hash, 16) != -1 + ) + is_valid_loop_counter = ( + LINEAGE_MIN_LOOP_REQUEST_COUNTER <= loop_counter <= LINEAGE_MAX_LOOP_COUNTER + ) + is_valid_request_counter = ( + LINEAGE_MIN_LOOP_REQUEST_COUNTER + <= request_counter + <= LINEAGE_MAX_REQUEST_COUNTER + ) + + return is_hash_valid and is_valid_loop_counter and is_valid_request_counter + + @staticmethod + def _parse_natural_or_return_negative(value, base): + try: + val = int(value, base) + + if val < 0: + return -1 + return val + except ValueError: + return -1 + def inject( self, carrier: CarrierT, @@ -315,10 +384,20 @@ def inject( ] ) + lineage = baggage.get_baggage(LINEAGE_KEY, context=context) + + if lineage is not None: + trace_header += ( + f"{KV_PAIR_DELIMITER}{LINEAGE_KEY}{KEY_AND_VALUE_DELIMITER}{lineage}" + ) + + # 256 character truncation + truncated_trace_header = trace_header[:256] + setter.set( carrier, TRACE_HEADER_KEY, - trace_header, + truncated_trace_header, ) @property diff --git a/propagator/opentelemetry-propagator-aws-xray/tests/test_aws_xray_propagator.py b/propagator/opentelemetry-propagator-aws-xray/tests/test_aws_xray_propagator.py index 2fb8a4925c..4147544603 100644 --- a/propagator/opentelemetry-propagator-aws-xray/tests/test_aws_xray_propagator.py +++ b/propagator/opentelemetry-propagator-aws-xray/tests/test_aws_xray_propagator.py @@ -17,6 +17,7 @@ from requests.structures import CaseInsensitiveDict +from opentelemetry import baggage import opentelemetry.trace as trace_api from opentelemetry.context import Context from opentelemetry.propagators.aws.aws_xray_propagator import ( @@ -33,6 +34,8 @@ set_span_in_context, ) +LINEAGE_KEY = "Lineage" + TRACE_ID_BASE16 = "8a3c60f7d188f8fa79d48a391a778fa6" SPAN_ID_BASE16 = "53995c3f42cd8ad8" @@ -114,14 +117,58 @@ def test_inject_into_non_sampled_context(self): self.assertEqual(injected_items, expected_items) + def test_inject_with_non_lineage_baggage(self): + context = build_test_current_context() + context.update( + baggage.set_baggage("cat", "meow", baggage.set_baggage("dog", "woof")) + ) + + carrier = CaseInsensitiveDict() + + AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject(carrier, context) + + injected_items = set(carrier.items()) + expected_items = set( + CaseInsensitiveDict( + { + TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0" + } + ).items() + ) + + self.assertEqual(injected_items, expected_items) + + def test_inject_with_lineage_baggage(self): + context = build_test_current_context() + context.update( + baggage.set_baggage( + LINEAGE_KEY, + "32767:e65a2c4d:255", + baggage.set_baggage("cat", "meow", baggage.set_baggage("dog", "bark")), + ) + ) + + carrier = CaseInsensitiveDict() + + AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject(carrier, context) + + injected_items = set(carrier.items()) + expected_items = set( + CaseInsensitiveDict( + { + TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=32767:e65a2c4d:255" + } + ).items() + ) + + self.assertEqual(injected_items, expected_items) + def test_inject_into_sampled_context(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( carrier, - build_test_current_context( - trace_flags=TraceFlags(TraceFlags.SAMPLED) - ), + build_test_current_context(trace_flags=TraceFlags(TraceFlags.SAMPLED)), ) injected_items = set(carrier.items()) @@ -140,9 +187,7 @@ def test_inject_into_context_with_non_default_state(self): AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( carrier, - build_test_current_context( - trace_state=TraceState([("foo", "bar")]) - ), + build_test_current_context(trace_state=TraceState([("foo", "bar")])), ) # TODO: (NathanielRN) Assert trace state when the propagator supports it @@ -167,9 +212,7 @@ def test_inject_reported_fields_matches_carrier_fields(self): injected_keys = set(carrier.keys()) - self.assertEqual( - injected_keys, AwsXRayPropagatorTest.XRAY_PROPAGATOR.fields - ) + self.assertEqual(injected_keys, AwsXRayPropagatorTest.XRAY_PROPAGATOR.fields) # Extract Tests @@ -211,9 +254,7 @@ def test_extract_sampled_context(self): self.assertEqual( get_nested_span_context(context_with_extracted), - build_test_span_context( - trace_flags=TraceFlags(TraceFlags.SAMPLED) - ), + build_test_span_context(trace_flags=TraceFlags(TraceFlags.SAMPLED)), ) def test_extract_different_order(self): @@ -230,20 +271,80 @@ def test_extract_different_order(self): build_test_span_context(), ) - def test_extract_with_additional_fields(self): + def test_extract_with_valid_lineage(self): + lineage = "32767:e65a2c4d:255" context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict( { - TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Foo=Bar" + TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=32767:e65a2c4d:255" } ), ) + self.assertEqual(baggage.get_baggage(LINEAGE_KEY, context=context_with_extracted), lineage) + self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) + def test_extract_with_invalid_lineage(self): + invalid_lineages = [ + "1::", + "1", + "", + ":", + "::", + "1:badc0de:13", + ":fbadc0de:13", + "1:fbadc0de:", + "1::1", + "65535:fbadc0de:255", + "-213:e65a2c4d:255", + "213:e65a2c4d:-22", + ] + for lineage in invalid_lineages: + trace_header = f"Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage={lineage}" + with self.subTest(trace_header=trace_header): + ctx = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( + CaseInsensitiveDict({TRACE_HEADER_KEY: trace_header}), + ) + + self.assertEqual( + get_nested_span_context(ctx), + build_test_span_context(), + ) + + self.assertEqual(ctx.get(LINEAGE_KEY), None) + + def test_extract_added_lineage_preserves_existing_baggage(self): + lineage = "32767:e65a2c4d:255" + expected_baggage_context = baggage.set_baggage( + "Lineage", + lineage, + baggage.set_baggage("cat", "meow", baggage.set_baggage("dog", "bark")), + ) + + cxt = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( + CaseInsensitiveDict( + { + TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=32767:e65a2c4d:255" + } + ), + context=baggage.set_baggage( + "cat", "meow", baggage.set_baggage("dog", "bark") + ), + ) + + self.assertEqual( + baggage.get_all(expected_baggage_context), baggage.get_all(cxt) + ) + + self.assertEqual( + get_nested_span_context(cxt), + build_test_span_context(), + ) + def test_extract_with_extra_whitespace(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict( @@ -307,6 +408,40 @@ def test_extract_invalid_to_implicit_ctx(self): self.assertDictEqual(Context(), ctx) + # Extract Inject Tests + + def test_extract_inject_valid_lineage(self): + getter_carrier = CaseInsensitiveDict( + { + TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=32767:e65a2c4d:255" + } + ) + setter_carrier = CaseInsensitiveDict() + + extract_ctx = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract(getter_carrier, build_test_current_context()) + + self.assertEqual(baggage.get_baggage(LINEAGE_KEY, extract_ctx), "32767:e65a2c4d:255") + + AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject(setter_carrier, extract_ctx) + + self.assertEqual(setter_carrier.get(TRACE_HEADER_KEY), 'Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=32767:e65a2c4d:255') + + def test_extract_inject_invalid_lineage(self): + getter_carrier = CaseInsensitiveDict( + { + TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=1:badc0de:13" + } + ) + setter_carrier = CaseInsensitiveDict() + + extract_ctx = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract(getter_carrier, build_test_current_context()) + + self.assertEqual(baggage.get_baggage(LINEAGE_KEY, extract_ctx), None) + + AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject(setter_carrier, extract_ctx) + + self.assertEqual(setter_carrier.get(TRACE_HEADER_KEY), 'Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0') + @patch("opentelemetry.propagators.aws.aws_xray_propagator.trace") def test_fields(self, mock_trace): """Make sure the fields attribute returns the fields used in inject""" @@ -332,6 +467,4 @@ def test_fields(self, mock_trace): for call in mock_setter.mock_calls: inject_fields.add(call[1][1]) - self.assertEqual( - AwsXRayPropagatorTest.XRAY_PROPAGATOR.fields, inject_fields - ) + self.assertEqual(AwsXRayPropagatorTest.XRAY_PROPAGATOR.fields, inject_fields) From 35630bcd5168da1bc87670a4bcaa52c57eed8b75 Mon Sep 17 00:00:00 2001 From: liustve Date: Tue, 28 Jan 2025 20:17:41 +0000 Subject: [PATCH 2/4] fixed formatting --- .../propagators/aws/aws_xray_propagator.py | 3 +- .../tests/test_aws_xray_propagator.py | 38 +++++++++++++------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py index e9a456451f..f3b3f089eb 100644 --- a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py +++ b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py @@ -318,7 +318,8 @@ def _is_valid_lineage(key): is_hash_valid = ( len(lineage_hash) == LINEAGE_HASH_LENGTH - and AwsXRayPropagator._parse_natural_or_return_negative(lineage_hash, 16) != -1 + and AwsXRayPropagator._parse_natural_or_return_negative(lineage_hash, 16) + != -1 ) is_valid_loop_counter = ( LINEAGE_MIN_LOOP_REQUEST_COUNTER <= loop_counter <= LINEAGE_MAX_LOOP_COUNTER diff --git a/propagator/opentelemetry-propagator-aws-xray/tests/test_aws_xray_propagator.py b/propagator/opentelemetry-propagator-aws-xray/tests/test_aws_xray_propagator.py index 4147544603..3151f3a8e8 100644 --- a/propagator/opentelemetry-propagator-aws-xray/tests/test_aws_xray_propagator.py +++ b/propagator/opentelemetry-propagator-aws-xray/tests/test_aws_xray_propagator.py @@ -92,7 +92,7 @@ def build_test_span_context( trace_state, ) - +# pylint: disable=R0904 class AwsXRayPropagatorTest(unittest.TestCase): XRAY_PROPAGATOR = AwsXRayPropagator() @@ -281,7 +281,9 @@ def test_extract_with_valid_lineage(self): ), ) - self.assertEqual(baggage.get_baggage(LINEAGE_KEY, context=context_with_extracted), lineage) + self.assertEqual( + baggage.get_baggage(LINEAGE_KEY, context=context_with_extracted), lineage + ) self.assertEqual( get_nested_span_context(context_with_extracted), @@ -417,14 +419,21 @@ def test_extract_inject_valid_lineage(self): } ) setter_carrier = CaseInsensitiveDict() - - extract_ctx = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract(getter_carrier, build_test_current_context()) - self.assertEqual(baggage.get_baggage(LINEAGE_KEY, extract_ctx), "32767:e65a2c4d:255") + extract_ctx = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( + getter_carrier, build_test_current_context() + ) + + self.assertEqual( + baggage.get_baggage(LINEAGE_KEY, extract_ctx), "32767:e65a2c4d:255" + ) AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject(setter_carrier, extract_ctx) - - self.assertEqual(setter_carrier.get(TRACE_HEADER_KEY), 'Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=32767:e65a2c4d:255') + + self.assertEqual( + setter_carrier.get(TRACE_HEADER_KEY), + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Lineage=32767:e65a2c4d:255", + ) def test_extract_inject_invalid_lineage(self): getter_carrier = CaseInsensitiveDict( @@ -433,15 +442,20 @@ def test_extract_inject_invalid_lineage(self): } ) setter_carrier = CaseInsensitiveDict() - - extract_ctx = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract(getter_carrier, build_test_current_context()) + + extract_ctx = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( + getter_carrier, build_test_current_context() + ) self.assertEqual(baggage.get_baggage(LINEAGE_KEY, extract_ctx), None) AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject(setter_carrier, extract_ctx) - - self.assertEqual(setter_carrier.get(TRACE_HEADER_KEY), 'Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0') - + + self.assertEqual( + setter_carrier.get(TRACE_HEADER_KEY), + "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0", + ) + @patch("opentelemetry.propagators.aws.aws_xray_propagator.trace") def test_fields(self, mock_trace): """Make sure the fields attribute returns the fields used in inject""" From 28dc3ad342c6fced0d25223f8b1acaffe2f4dd85 Mon Sep 17 00:00:00 2001 From: liustve Date: Thu, 30 Jan 2025 18:46:47 +0000 Subject: [PATCH 3/4] updated changelog --- propagator/opentelemetry-propagator-aws-xray/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/propagator/opentelemetry-propagator-aws-xray/CHANGELOG.md b/propagator/opentelemetry-propagator-aws-xray/CHANGELOG.md index bdbcdef927..b2e53145c6 100644 --- a/propagator/opentelemetry-propagator-aws-xray/CHANGELOG.md +++ b/propagator/opentelemetry-propagator-aws-xray/CHANGELOG.md @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update `opentelemetry-api` version to 1.16 ([#2961](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2961)) +- Added support for Lambda Lineage to XRay Trace Header + ([#3223](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3223)) + ## Version 1.0.2 (2024-08-05) See [common CHANGELOG](../../CHANGELOG.md) for the changes in this and prior versions. From 9163a4e81185e85ac0e72d07b4cfc53c2b11b97d Mon Sep 17 00:00:00 2001 From: liustve Date: Mon, 3 Feb 2025 18:50:19 +0000 Subject: [PATCH 4/4] updated var names --- .../propagators/aws/aws_xray_propagator.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py index f3b3f089eb..94e0e96d92 100644 --- a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py +++ b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py @@ -97,9 +97,9 @@ LINEAGE_MAX_LENGTH = 18 LINEAGE_MIN_LENGTH = 12 LINEAGE_HASH_LENGTH = 8 -LINEAGE_MAX_LOOP_COUNTER = 32767 -LINEAGE_MAX_REQUEST_COUNTER = 255 -LINEAGE_MIN_LOOP_REQUEST_COUNTER = 0 +LINEAGE_MAX_COUNTER1 = 32767 +LINEAGE_MAX_COUNTER2 = 255 +LINEAGE_MIN_COUNTER = 0 INVALID_LINEAGE_HEADER = "-1:11111111:0" @@ -311,8 +311,8 @@ def _parse_lineage_header(xray_lineage_header): def _is_valid_lineage(key): split = key.split(LINEAGE_DELIMITER) lineage_hash = split[1] - loop_counter = AwsXRayPropagator._parse_natural_or_return_negative(split[0], 10) - request_counter = AwsXRayPropagator._parse_natural_or_return_negative( + counter1 = AwsXRayPropagator._parse_natural_or_return_negative(split[0], 10) + counter2 = AwsXRayPropagator._parse_natural_or_return_negative( split[2], 10 ) @@ -321,16 +321,16 @@ def _is_valid_lineage(key): and AwsXRayPropagator._parse_natural_or_return_negative(lineage_hash, 16) != -1 ) - is_valid_loop_counter = ( - LINEAGE_MIN_LOOP_REQUEST_COUNTER <= loop_counter <= LINEAGE_MAX_LOOP_COUNTER + is_valid_counter1 = ( + LINEAGE_MIN_COUNTER <= counter1 <= LINEAGE_MAX_COUNTER1 ) - is_valid_request_counter = ( - LINEAGE_MIN_LOOP_REQUEST_COUNTER - <= request_counter - <= LINEAGE_MAX_REQUEST_COUNTER + is_valid_counter2 = ( + LINEAGE_MIN_COUNTER + <= counter2 + <= LINEAGE_MAX_COUNTER2 ) - return is_hash_valid and is_valid_loop_counter and is_valid_request_counter + return is_hash_valid and is_valid_counter1 and is_valid_counter2 @staticmethod def _parse_natural_or_return_negative(value, base):