def __encode_instruction( instruction: "CompiledInstruction", ) -> bytes: # TODO: Replace this with a construct struct. InstructionFormat = NamedTuple( "InstructionFormat", [ ("program_idx", bytes), ("accounts_length", bytes), ("accounts", bytes), ("data_length", bytes), ("data", bytes), ], ) data = b58decode(instruction.data) data_length = shortvec.encode_length(len(data)) return b"".join( InstructionFormat( program_idx=helpers.to_uint8_bytes( instruction.program_id_index), accounts_length=shortvec.encode_length( len(instruction.accounts)), accounts=bytes(instruction.accounts), data_length=data_length, data=data, ))
def serialize(self) -> bytes: """Serialize message to bytes. >>> from solana.blockhash import Blockhash >>> account_keys = [str(PublicKey(i + 1)) for i in range(5)] >>> msg = Message( ... MessageArgs( ... account_keys=account_keys, ... header=MessageHeader( ... num_readonly_signed_accounts=0, num_readonly_unsigned_accounts=3, num_required_signatures=2 ... ), ... instructions=[ ... CompiledInstruction(accounts=[1, 2, 3], data=b58encode(bytes([9] * 5)), program_id_index=4)], ... recent_blockhash=Blockhash("EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k"), ... ) ... ) >>> msg.serialize().hex() '0200030500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005c49ae77603782054f17a9decea43b444eba0edb12c6f1d31c6e0e4a84bf052eb010403010203050909090909' """ # pylint: disable=line-too-long message_buffer = bytearray() # Message body message_buffer.extend(self.__encode_message()) # Instructions instruction_count = shortvec.encode_length(len(self.instructions)) message_buffer.extend(instruction_count) for instr in self.instructions: message_buffer.extend(Message.__encode_instruction(instr)) return bytes(message_buffer)
def __encode_message( self) -> bytes: # TODO: Replace this with a construct struct. MessageFormat = NamedTuple( "MessageFormat", [ ("num_required_signatures", bytes), ("num_readonly_signed_accounts", bytes), ("num_readonly_unsigned_accounts", bytes), ("pubkeys_length", bytes), ("pubkeys", bytes), ("recent_blockhash", bytes), ], ) return b"".join( MessageFormat( num_required_signatures=helpers.to_uint8_bytes( self.header.num_required_signatures), num_readonly_signed_accounts=helpers.to_uint8_bytes( self.header.num_readonly_signed_accounts), num_readonly_unsigned_accounts=helpers.to_uint8_bytes( self.header.num_readonly_unsigned_accounts), pubkeys_length=shortvec.encode_length(len(self.account_keys)), pubkeys=b"".join( [bytes(pubkey) for pubkey in self.account_keys]), recent_blockhash=b58decode( self.recent_blockhash.encode("ascii")), ))
def __serialize(self, signed_data: bytes) -> bytes: if len(self.signatures) >= SIG_LENGTH * 4: raise AttributeError("too many singatures to encode") wire_transaction = bytearray() # Encode signature count signature_count = shortvec.encode_length(len(self.signatures)) wire_transaction.extend(signature_count) # Encode signatures for sig_pair in self.signatures: if sig_pair.signature and len(sig_pair.signature) != SIG_LENGTH: raise RuntimeError("signature has invalid length", sig_pair.signature) if not sig_pair.signature: wire_transaction.extend(bytearray(SIG_LENGTH)) else: wire_transaction.extend(sig_pair.signature) # Encode signed data wire_transaction.extend(signed_data) if len(wire_transaction) > PACKET_DATA_SIZE: raise RuntimeError( f"transaction too large: {len(wire_transaction)} > {PACKET_DATA_SIZE}" ) return bytes(wire_transaction)
def assert_encoded_array(buffer: bytearray, length: int, prev_length: int, expected: List[int]) -> None: """Helper to encode length of an array.""" assert len(buffer) == prev_length actual = encode_length(length) buffer.extend(actual) assert len(buffer) == prev_length + len(expected) assert bytes(buffer[-len(expected) :]) == bytes(expected) # noqa: 203
def assert_encoded_array(buffer: bytearray, length: int, prev_length: int, expected: List[int]) -> bytearray: assert len(buffer) == prev_length actual = encode_length(length) buffer.extend(actual) assert len(buffer) == prev_length + len(expected) assert bytes(buffer[-len(expected):]) == bytes(expected) # noqa: 203 return buffer