def send_transaction( self, txn: Transaction, *signers: Account, opts: types.TxOpts = types.TxOpts() ) -> types.RPCResponse: """Send a transaction. :param txn: Transaction object. :param signers: Signers to sign the transaction. :param opts: (optional) Transaction options. >>> from solana.account import Account >>> from solana.system_program import TransferParams, transfer >>> from solana.transaction import Transaction >>> sender, reciever = Account(1), Account(2) >>> txn = Transaction().add(transfer(TransferParams( ... from_pubkey=sender.public_key(), to_pubkey=reciever.public_key(), lamports=1000))) >>> solana_client = Client("http://localhost:8899") >>> solana_client.send_transaction(txn, sender) # doctest: +SKIP {'jsonrpc': '2.0', 'result': '236zSA5w4NaVuLXXHK1mqiBuBxkNBu84X6cfLBh1v6zjPrLfyECz4zdedofBaZFhs4gdwzSmij9VkaSo2tR5LTgG', 'id': 12} """ try: # TODO: Cache recent blockhash blockhash_resp = self.get_recent_blockhash() if not blockhash_resp["result"]: raise RuntimeError("failed to get recent blockhash") txn.recent_blockhash = Blockhash(blockhash_resp["result"]["value"]["blockhash"]) except Exception as err: raise RuntimeError("failed to get recent blockhash") from err txn.sign(*signers) return self.send_raw_transaction(txn.serialize(), opts=opts)
def send_transaction(self, txn: Transaction, *signers: Account) -> RPCResponse: """Send a transaction. :param txn: Transaction object. :param signers: Signers to sign the transaction >>> from solana.account import Account >>> from solana.system_program import TransferParams, transfer >>> sender, reciever = Account(1), Account(2) >>> tx = transfer(TransferParams( ... from_pubkey=sender.public_key(), to_pubkey=reciever.public_key(), lamports=1000)) >>> solana_client = Client("http://localhost:8899") >>> solana_client.send_transaction(tx, sender) # doctest: +SKIP {'jsonrpc': '2.0', 'result': '236zSA5w4NaVuLXXHK1mqiBuBxkNBu84X6cfLBh1v6zjPrLfyECz4zdedofBaZFhs4gdwzSmij9VkaSo2tR5LTgG', 'id': 12} """ try: # TODO: Cache recent blockhash blockhash_resp = self.get_recent_blockhash() if not blockhash_resp["result"]: raise RuntimeError("failed to get recent blockhash") txn.recent_blockhash = Blockhash( blockhash_resp["result"]["value"]["blockhash"]) except Exception as err: raise RuntimeError("failed to get recent blockhash") from err txn.sign(*signers) wire_format = b58encode(txn.serialize()).decode("utf-8") return self._provider.make_request(RPCMethod("sendTransaction"), wire_format)
def _validate_txsize(self) -> bool: tx = self.build_tx() # Predefined blockhash is used only to check transaction size, this transaction won't be send to network tx.recent_blockhash = Blockhash( '4NCYB3kRT8sCNodPNuCZo8VUh4xqpBQxsxed2wd9xaD4') tx.sign(self.s.resource.signer) try: tx.serialize() return True except Exception as err: if check_if_big_transaction(err): self.error = 'Too big transaction size' return False self.error = str(err) raise
def deserialize(raw_message: bytes) -> Message: """Deserialize raw message bytes. >>> raw_message = bytes.fromhex( ... '0200030500000000000000000000000000000000000000000000' ... '0000000000000000000100000000000000000000000000000000' ... '0000000000000000000000000000000200000000000000000000' ... '0000000000000000000000000000000000000000000300000000' ... '0000000000000000000000000000000000000000000000000000' ... '0004000000000000000000000000000000000000000000000000' ... '0000000000000005c49ae77603782054f17a9decea43b444eba0' ... 'edb12c6f1d31c6e0e4a84bf052eb010403010203050909090909' ... ) >>> type(Message.deserialize(raw_message)) <class 'solana.message.Message'> """ HEADER_OFFSET = 3 # pylint: disable=invalid-name if len(raw_message) < HEADER_OFFSET: raise ValueError("byte representation of message is missing message header") num_required_signatures = raw_message[0] num_readonly_signed_accounts = raw_message[1] num_readonly_unsigned_accounts = raw_message[2] header = MessageHeader( num_required_signatures=num_required_signatures, num_readonly_signed_accounts=num_readonly_signed_accounts, num_readonly_unsigned_accounts=num_readonly_unsigned_accounts, ) raw_message = raw_message[HEADER_OFFSET:] account_keys = [] accounts_length, accounts_offset = shortvec.decode_length(raw_message) for _ in range(accounts_length): key_bytes = raw_message[accounts_offset : accounts_offset + PublicKey.LENGTH] # noqa: E203 account_keys.append(str(PublicKey(key_bytes))) accounts_offset += PublicKey.LENGTH raw_message = raw_message[accounts_offset:] recent_blockhash = Blockhash(b58encode(raw_message[: PublicKey.LENGTH]).decode("utf-8")) raw_message = raw_message[PublicKey.LENGTH :] # noqa: E203 instructions = [] instruction_count, offset = shortvec.decode_length(raw_message) raw_message = raw_message[offset:] for _ in range(instruction_count): program_id_index = raw_message[0] raw_message = raw_message[1:] accounts_length, offset = shortvec.decode_length(raw_message) raw_message = raw_message[offset:] accounts = raw_message[:accounts_length] raw_message = raw_message[accounts_length:] data_length, offset = shortvec.decode_length(raw_message) raw_message = raw_message[offset:] data = b58encode(raw_message[:data_length]) raw_message = raw_message[data_length:] instructions.append(CompiledInstruction(program_id_index=program_id_index, accounts=accounts, data=data)) return Message( MessageArgs( header=header, account_keys=account_keys, recent_blockhash=recent_blockhash, instructions=instructions, ) )
def parse_recent_blockhash(blockhash_resp: types.RPCResponse) -> Blockhash: """Extract blockhash from JSON RPC result.""" if not blockhash_resp.get("result"): raise RuntimeError("failed to get recent blockhash") return Blockhash(blockhash_resp["result"]["value"]["blockhash"])
def stubbed_blockhash() -> Blockhash: """Arbitrary block hash.""" return Blockhash("EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k")