Serialization: objects, arrays, hashes

This commit is contained in:
mDuo13
2018-11-21 16:32:44 -08:00
parent 74190e435e
commit 8240872c56
5 changed files with 225 additions and 15 deletions

View File

@@ -39,6 +39,11 @@ def field_sort_key(field_name):
return (DEFINITIONS["TYPES"][field_type_name], DEFINITIONS["FIELDS"][field_name]["nth"])
def field_id(field_name):
"""
Returns the unique field ID for a given field name.
This field ID consists of the type code and field code, in 1 to 3 bytes
depending on whether those values are "common" (<16) or uncommon (>=16)
"""
field_type_name = DEFINITIONS["FIELDS"][field_name]["type"]
type_code = DEFINITIONS["TYPES"][field_type_name]
field_code = DEFINITIONS["FIELDS"][field_name]["nth"]
@@ -145,10 +150,59 @@ def vl_to_bytes(field_val):
vl_contents = bytes.fromhex(field_val)
return vl_encode(vl_contents)
def hash_to_bytes(contents):
return bytes.fromhex(field_val)
def accountid_to_bytes(address):
return vl_encode(decode_address(address))
def array_to_bytes(array):
"""
Serialize an array of objects.
Each member object must have a type wrapper and an inner object.
"""
members_as_bytes = []
for el in array:
wrapper_key = list(el.keys())[0]
inner_obj = el[wrapper_key]
members_as_bytes.append(field_to_bytes(field_name=wrapper_key, field_val=el))
members_as_bytes.append(field_id("ArrayEndMarker"))
return b''.join(members_as_bytes)
def object_to_bytes(obj):
"""
Serialize an object, assuming a type wrapper, for example:
{
"SignerEntry": {
"Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
"SignerWeight": 1
}
}
Puts the child fields (e.g. Account, SignerWeight) in canonical order
and appends an object end marker.
"""
wrapper_key = list(obj.keys())[0]
inner_obj = obj[wrapper_key]
child_order = sorted(inner_obj.keys(), key=field_sort_key)
fields_as_bytes = []
for field_name in child_order:
if (DEFINITIONS["FIELDS"][field_name]["isSerialized"]):
field_val = inner_obj[field_name]
field_bytes = field_to_bytes(field_name, field_val)
logger.debug("{n}: {h}".format(n=field_name, h=field_bytes.hex()))
fields_as_bytes.append(field_bytes)
fields_as_bytes.append(field_id("ObjectEndMarker"))
return b''.join(fields_as_bytes)
def field_to_bytes(field_name, field_val):
"""
Returns a bytes object containing the serialized version of a field
including its field ID prefix.
"""
field_type = DEFINITIONS["FIELDS"][field_name]["type"]
logger.debug("Serializing field {f} of type {t}".format(f=field_name, t=field_type))
@@ -161,13 +215,19 @@ def field_to_bytes(field_name, field_val):
dispatch = {
# TypeName: function(field): bytes object
"UInt64": lambda x:bytes_from_uint(x, 64),
"UInt32": lambda x:bytes_from_uint(x, 32),
"UInt16": lambda x:bytes_from_uint(x, 16),
"UInt8" : lambda x:bytes_from_uint(x, 8),
"AccountID": accountid_to_bytes,
"Amount": amount_to_bytes,
"Blob": vl_to_bytes
"Blob": vl_to_bytes,
"Hash128": hash_to_bytes,
"Hash160": hash_to_bytes,
"Hash256": hash_to_bytes,
# TODO: PathSet
"STArray": array_to_bytes,
"STObject": object_to_bytes,
"UInt8" : lambda x:bytes_from_uint(x, 8),
"UInt16": lambda x:bytes_from_uint(x, 16),
"UInt32": lambda x:bytes_from_uint(x, 32),
"UInt64": lambda x:bytes_from_uint(x, 64),
}
field_binary = dispatch[field_type](field_val)
return b''.join( (id_prefix, field_binary) )
@@ -210,7 +270,7 @@ if __name__ == "__main__":
# "Sequence": 2
# }
with open("test-cases/tx1-nometa.json") as f:
with open("test-cases/tx2-nometa.json") as f:
example_tx = json.load(f)
serialize_tx(example_tx)

View File

@@ -0,0 +1 @@
1200022280000000240000000120190000000B68400000000000277573210268D79CD579D077750740FA18A2370B7C2018B2714ECE70BA65C38D223E79BC9C74473045022100F06FB54049D6D50142E5CF2E2AC21946AF305A13E2A2D4BA881B36484DD01A540220311557EC8BEF536D729605A4CB4D4DC51B1E37C06C93434DD5B7651E1E2E28BF811452C7F01AD13B3CA9C1D133FA8F3482D2EF08FA7D82145A380FBD236B6A1CD14B939AD21101E5B6B6FFA2F9EA7D0F04C4D46544659A2D58525043686174E1F1

View File

@@ -0,0 +1,94 @@
{
"hash": "C0B450C8601E19CB0BDED71C4B523B2A4AAB77415B08E7923D8DA3F831631702",
"ledger_index": 36259236,
"date": "2018-02-01T09:45:32+00:00",
"tx": {
"TransactionType": "EscrowFinish",
"Flags": 2147483648,
"Sequence": 1,
"OfferSequence": 11,
"Fee": "10101",
"SigningPubKey": "0268D79CD579D077750740FA18A2370B7C2018B2714ECE70BA65C38D223E79BC9C",
"TxnSignature": "3045022100F06FB54049D6D50142E5CF2E2AC21946AF305A13E2A2D4BA881B36484DD01A540220311557EC8BEF536D729605A4CB4D4DC51B1E37C06C93434DD5B7651E1E2E28BF",
"Account": "r3Y6vCE8XqfZmYBRngy22uFYkmz3y9eCRA",
"Owner": "r9NpyVfLfUG8hatuCCHKzosyDtKnBdsEN3",
"Memos": [
{
"Memo": {
"MemoData": "04C4D46544659A2D58525043686174"
}
}
]
},
"meta": {
"TransactionIndex": 35,
"AffectedNodes": [
{
"DeletedNode": {
"LedgerEntryType": "Escrow",
"LedgerIndex": "983EBDF89C1C30CECDB105B593E7DEBE602AF89012EDB4DD76D24ACEF92C89EF",
"FinalFields": {
"Flags": 0,
"PreviousTxnLgrSeq": 35059511,
"FinishAfter": 570758400,
"OwnerNode": "0000000000000000",
"PreviousTxnID": "6F54E04D7B205CBE2FCAEF1C249E62A9759721C7FE1F6992FD800266C8E4814C",
"Amount": "1000000000000000",
"Account": "r9NpyVfLfUG8hatuCCHKzosyDtKnBdsEN3",
"Destination": "r9NpyVfLfUG8hatuCCHKzosyDtKnBdsEN3"
}
}
},
{
"ModifiedNode": {
"LedgerEntryType": "DirectoryNode",
"LedgerIndex": "C05DC35EBDCA5D8697190FF41950EC5AFCBF7F61C1177DC73000CC17C2149886",
"FinalFields": {
"Flags": 0,
"RootIndex": "C05DC35EBDCA5D8697190FF41950EC5AFCBF7F61C1177DC73000CC17C2149886",
"Owner": "r9NpyVfLfUG8hatuCCHKzosyDtKnBdsEN3"
}
}
},
{
"ModifiedNode": {
"LedgerEntryType": "AccountRoot",
"PreviousTxnLgrSeq": 36230933,
"PreviousTxnID": "9366F75CD350ACE0EEFC0A392ECBD5AC2B84C06E5DEC2DE895B76FFC7BD55553",
"LedgerIndex": "C180CA555CE8820D8F1086CDCA756FF8D5813FEB2AE3FF002B9F48F870CA08A0",
"PreviousFields": {
"Sequence": 1,
"Balance": "26000000"
},
"FinalFields": {
"Flags": 0,
"Sequence": 2,
"OwnerCount": 0,
"Balance": "25989899",
"Account": "r3Y6vCE8XqfZmYBRngy22uFYkmz3y9eCRA"
}
}
},
{
"ModifiedNode": {
"LedgerEntryType": "AccountRoot",
"PreviousTxnLgrSeq": 36253527,
"PreviousTxnID": "F2AA5584005847C19F59A9C87E7BF3108F97F2567C5083159EEC40B08ED90F46",
"LedgerIndex": "DCED5AAFE87AA8D00E651DBBFBA2F992927BC3DC5FFD905EF49019ED02824B3A",
"PreviousFields": {
"OwnerCount": 14,
"Balance": "200923000"
},
"FinalFields": {
"Flags": 1048576,
"Sequence": 18,
"OwnerCount": 13,
"Balance": "1000000200923000",
"Account": "r9NpyVfLfUG8hatuCCHKzosyDtKnBdsEN3"
}
}
}
],
"TransactionResult": "tesSUCCESS"
}
}

View File

@@ -0,0 +1,18 @@
{
"TransactionType": "EscrowFinish",
"Flags": 2147483648,
"Sequence": 1,
"OfferSequence": 11,
"Fee": "10101",
"SigningPubKey": "0268D79CD579D077750740FA18A2370B7C2018B2714ECE70BA65C38D223E79BC9C",
"TxnSignature": "3045022100F06FB54049D6D50142E5CF2E2AC21946AF305A13E2A2D4BA881B36484DD01A540220311557EC8BEF536D729605A4CB4D4DC51B1E37C06C93434DD5B7651E1E2E28BF",
"Account": "r3Y6vCE8XqfZmYBRngy22uFYkmz3y9eCRA",
"Owner": "r9NpyVfLfUG8hatuCCHKzosyDtKnBdsEN3",
"Memos": [
{
"Memo": {
"MemoData": "04C4D46544659A2D58525043686174"
}
}
]
}