diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e7010c23..34bd5e2ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [[Unreleased]] +### Added +- decode_ledger_data utility method is useful for parsing serialized ledger-headers + ## [4.0.0] - 2024-12-23 ### Added @@ -95,6 +98,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2.0.0] - 2023-07-05 ### BREAKING CHANGE - The default signing algorithm in the `Wallet` was changed from secp256k1 to ed25519 + ### Added: - Wallet support for regular key compatibility - Added new ways of wallet generation: `from_seed`, `from_secret`, `from_entropy`, `from_secret_numbers` diff --git a/tests/unit/core/binarycodec/fixtures/data/codec-fixtures.json b/tests/unit/core/binarycodec/fixtures/data/codec-fixtures.json index fa30a927e..907f32893 100644 --- a/tests/unit/core/binarycodec/fixtures/data/codec-fixtures.json +++ b/tests/unit/core/binarycodec/fixtures/data/codec-fixtures.json @@ -4842,7 +4842,7 @@ } ], "ledgerData": [{ - "binary": "01E91435016340767BF1C4A3EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F873B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D521276CDE21276CE60A00", + "serialized_data": "01E91435016340767BF1C4A3EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F873B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D521276CDE21276CE60A00", "json": { "account_hash": "3B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D5", "close_flags": 0, @@ -4854,5 +4854,31 @@ "total_coins": "99994494362043555", "transaction_hash": "DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F87" } + }, { + "serialized_data": "058973980163396C087559B1361DA99E35E60A7A769473C536F4D2218C75872CD23FB76701C0C4A7D5DDD34B52F011B54E84BEC1E84C509ADEB64111AE2D7B6082B2065A70A1538678DF1ED14E8D02783F8E4F47A636BB73264EEADAAF93FA1DC10E8BFA9FEDE1E436313EE22EF7E1202EF7E1210A00", + "json": { + "account_hash": "4E8D02783F8E4F47A636BB73264EEADAAF93FA1DC10E8BFA9FEDE1E436313EE2", + "close_flags": 0, + "close_time": 787996961, + "close_time_resolution": 10, + "parent_close_time": 787996960, + "parent_hash": "361DA99E35E60A7A769473C536F4D2218C75872CD23FB76701C0C4A7D5DDD34B", + "total_coins": "99986752893442481", + "transaction_hash": "52F011B54E84BEC1E84C509ADEB64111AE2D7B6082B2065A70A1538678DF1ED1", + "ledger_index": 92894104 + } + }, { + "serialized_data": "058974040163396C0704FF8BBB7676027C39A0BF54ACA8B472CD2D39CBB83AE9612FF6E129E1FE6237A7D75AE1D62183ED82F39825A20199251427D1DEBFD46C1AABAA473DDFDB93ABBAF9CDD7C48AD76715EE257DBF64BE4248827A147E59F90D1905174C47D6878C278AB12EF7E2C42EF7E2C50A00", + "json": { + "account_hash": "D7C48AD76715EE257DBF64BE4248827A147E59F90D1905174C47D6878C278AB1", + "close_flags": 0, + "close_time": 787997381, + "close_time_resolution": 10, + "parent_close_time": 787997380, + "parent_hash": "BB7676027C39A0BF54ACA8B472CD2D39CBB83AE9612FF6E129E1FE6237A7D75A", + "total_coins": "99986752869302155", + "transaction_hash": "E1D62183ED82F39825A20199251427D1DEBFD46C1AABAA473DDFDB93ABBAF9CD", + "ledger_index": 92894212 + } }] } diff --git a/tests/unit/core/binarycodec/fixtures/data_driven_fixtures.py b/tests/unit/core/binarycodec/fixtures/data_driven_fixtures.py index 4f39c488d..cc7a9b60a 100644 --- a/tests/unit/core/binarycodec/fixtures/data_driven_fixtures.py +++ b/tests/unit/core/binarycodec/fixtures/data_driven_fixtures.py @@ -9,6 +9,20 @@ # top level keys: ['types', 'fields_tests', 'whole_objects', 'values_tests'] +def get_ledger_data_codec_test(): + """ + Fetch the (serialized, de-serialized) pairs of ledger_data from the + codec-fixtures.json file + """ + + with open( + "tests/unit/core/binarycodec/fixtures/data/codec-fixtures.json" + ) as codec_tests: + ledger_data = json.load(codec_tests)["ledgerData"] + + return ledger_data + + def get_field_tests(): """ Constructs and returns a list of FieldTest objects after parsing JSON data diff --git a/tests/unit/core/binarycodec/test_field_id_codec.py b/tests/unit/core/binarycodec/test_field_id_codec.py index 6bce4b2fe..7fffe4a94 100644 --- a/tests/unit/core/binarycodec/test_field_id_codec.py +++ b/tests/unit/core/binarycodec/test_field_id_codec.py @@ -2,6 +2,7 @@ import xrpl.core.binarycodec.field_id_codec as field_id_codec from tests.unit.core.binarycodec.fixtures import data_driven_fixtures +from xrpl.core.binarycodec.field_id_codec import decode_ledger_header class TestFieldIDCodec(TestCase): @@ -21,3 +22,11 @@ def test_encode(self): def test_decode(self): for test in self.field_tests: self.assertEqual(test.name, field_id_codec.decode(test.expected_hex)) + + +class TestDecodeLedgerHeader(TestCase): + def test_decode_ledger_header_valid(self): + for test in data_driven_fixtures.get_ledger_data_codec_test(): + self.assertEqual( + test["json"], decode_ledger_header(test["serialized_data"]) + ) diff --git a/xrpl/core/binarycodec/field_id_codec.py b/xrpl/core/binarycodec/field_id_codec.py index 21b7b6698..cb5874664 100644 --- a/xrpl/core/binarycodec/field_id_codec.py +++ b/xrpl/core/binarycodec/field_id_codec.py @@ -3,9 +3,44 @@ `Field IDs `_ """ +from typing import Any, Dict + +from xrpl.core.binarycodec.binary_wrappers import BinaryParser from xrpl.core.binarycodec.definitions import definitions from xrpl.core.binarycodec.definitions.field_header import FieldHeader from xrpl.core.binarycodec.exceptions import XRPLBinaryCodecException +from xrpl.core.binarycodec.types.hash256 import Hash256 +from xrpl.core.binarycodec.types.uint64 import UInt64 + + +def decode_ledger_header(serialized_str: str) -> Dict[str, Any]: + """ + Decodes a serialized ledger header. + Note: The file located at xrpl/core/binarycodec/definitions/definitions.json file + is used to parse the serialized data. If developers need custom definitions, + please update that file. + + Args: + serialized_str: A serialized ledger header, represented as a hexa-decimal string + + Returns: + A Dict object describing a ledger header + """ + parser = BinaryParser(serialized_str) + + return { + "ledger_index": parser.read_uint32(), + # Uint64 types are represented as hex-strings for preserving precision + # For ease of use, explicitly type-cast this value into base-10 + "total_coins": str(int(parser.read_type(UInt64).to_hex(), base=16)), + "parent_hash": parser.read_type(Hash256).to_hex(), + "transaction_hash": parser.read_type(Hash256).to_hex(), + "account_hash": parser.read_type(Hash256).to_hex(), + "parent_close_time": parser.read_uint32(), + "close_time": parser.read_uint32(), + "close_time_resolution": parser.read_uint8(), + "close_flags": parser.read_uint8(), + } def encode(field_name: str) -> bytes: