text: from io import BytesIO
  from unittest import TestCase
  
  import requests
  
  from ecc import PrivateKey, S256Point, Signature
  from helper import (
      decode_base58,
      double_sha256,
      encode_varint,
      int_to_little_endian,
      little_endian_to_int,
      read_varint,
      SIGHASH_ALL,
  )
  from script import p2pkh_script, Script
  
  
  class Tx:
  
      def __init__(self, version, tx_ins, tx_outs, locktime, testnet=False):
          self.version = version
          self.tx_ins = tx_ins
          self.tx_outs = tx_outs
          self.locktime = locktime
          self.testnet = testnet
  
      def __repr__(self):
          tx_ins = ''
          for tx_in in self.tx_ins:
              tx_ins += tx_in.__repr__() + '\n'
          tx_outs = ''
          for tx_out in self.tx_outs:
              tx_outs += tx_out.__repr__() + '\n'
          return 'tx: {}\nversion: {}\ntx_ins:\n{}\ntx_outs:\n{}\nlocktime: {}\n'.format(
              self.hash().hex(),
              self.version,
              tx_ins,
              tx_outs,
              self.locktime,
          )
  
      def hash(self):
          return double_sha256(self.serialize())[::-1]
  
      @classmethod
      def parse(cls, s, testnet=False):
          '''Takes a byte stream and parses the transaction at the start
          return a Tx object
          '''
          # s.read(n) will return n bytes
          # version has 4 bytes, little-endian, interpret as int
          version = little_endian_to_int(s.read(4))
          # num_inputs is a varint, use read_varint(s)
          num_inputs = read_varint(s)
          # each input needs parsing
          inputs = []
          for _ in range(num_inputs):
              inputs.append(TxIn.parse(s))
          # num_outputs is a varint, use read_varint(s)
          num_outputs = read_varint(s)
          # each output needs parsing
          outputs = []
          for _ in range(num_outputs):
              outputs.append(TxOut.parse(s))
          # locktime is 4 bytes, little-endian
          locktime = little_endian_to_int(s.read(4))
          # return an instance of the class (cls(...))
          return cls(version, inputs, outputs, locktime, testnet=testnet)
  
      def serialize(self):
          '''Returns the byte serialization of the transaction'''
          # serialize version (4 bytes, little endian)
          result = int_to_little_endian(self.version, 4)
          # encode_varint on the number of inputs
          result += encode_varint(len(self.tx_ins))
          # iterate inputs
          for tx_in in self.tx_ins:
              # serialize each input
              result += tx_in.serialize()
          # encode_varint on the number of outputs
          result += encode_varint(len(self.tx_outs))
          # iterate outputs
          for tx_out in self.tx_outs:
              # serialize each output
              result += tx_out.serialize()
          # serialize locktime (4 bytes, little endian)
          result += int_to_little_endian(self.locktime, 4)
          return result
  
      def fee(self):
          '''Returns the fee of this transaction in satoshi'''
          # initialize input sum and output sum
          input_sum, output_sum = 0, 0
          # iterate through inputs
          for tx_in in self.tx_ins:
              # for each input get the value and add to input sum
              input_sum += tx_in.value(self.testnet)
          # iterate through outputs
          for tx_out in self.tx_outs:
              # for each output get the amount and add to output sum
              output_sum += tx_out.amount
          # return input sum - output sum
          return input_sum - output_sum
  
      def sig_hash(self, input_index, hash_type):
          '''Returns the integer representation of the hash that needs to get
          signed for index input_index'''
          # create a new set of tx_ins (alt_tx_ins)
          alt_tx_ins = []
          # iterate over self.tx_ins
          for tx_in in self.tx_ins:
              # create a new TxIn that has a blank script_sig (b'') and add to alt_tx_ins
              alt_tx_ins.append(TxIn(
                  prev_tx=tx_in.prev_tx,
                  prev_index=tx_in.prev_index,
                  script_sig=Script([]),
                  sequence=tx_in.sequence,
              ))
          # grab the input at the input_index
          signing_input = alt_tx_ins[input_index]
          # grab the script_pubkey of the input
          script_pubkey = signing_input.script_pubkey(self.testnet)
          # the script_sig of the signing_input should be script_pubkey
          signing_input.script_sig = script_pubkey
          # create an alternate transaction with the modified tx_ins
          alt_tx = self.__class__(
              version=self.version,
              tx_ins=alt_tx_ins,
              tx_outs=self.tx_outs,
              locktime=self.locktime)
          # add the hash_type int 4 bytes, little endian
          result = alt_tx.serialize() + int_to_little_endian(hash_type, 4)
          # get the double_sha256 of the tx serialization
          s256 = double_sha256(result)
          # convert this to a big-endian integer using int.from_bytes(x, 'big')
          return int.from_bytes(s256, 'big')
  
      def verify_input(self, input_index):
          '''Returns whether the input has a valid signature'''
          # get the relevant input
          tx_in = self.tx_ins[input_index]
          # parse the point from the sec format (tx_in.sec_pubkey())
          point = S256Point.parse(tx_in.sec_pubkey())
          # parse the signature from the der format (tx_in.der_signature())
          signature = Signature.parse(tx_in.der_signature())
          # get the hash type from the input (tx_in.hash_type())
          hash_type = tx_in.hash_type()
          # get the sig_hash (z)
          z = self.sig_hash(input_index, hash_type)
          # use point.verify on the z and signature
          return point.verify(z, signature)
  
      def sign_input(self, input_index, private_key, hash_type):
          '''Signs the input using the private key'''
          # get the sig_hash (z)
          z = self.sig_hash(input_index, hash_type)
          # get der signature of z from private key
          der = private_key.sign(z).der()
          # append the hash_type to der (use hash_type.to_bytes(1, 'big'))
          sig = der + hash_type.to_bytes(1, 'big')
          # calculate the sec
          sec = private_key.point.sec()
          # initialize a new script with [sig, sec] as the elements
          script_sig = Script([sig, sec])
          # change input's script_sig to new script
          self.tx_ins[input_index].script_sig = script_sig
          # return whether sig is valid using self.verify_input
          return self.verify_input(input_index)
  
      def is_coinbase(self):
          '''Returns whether this transaction is a coinbase transaction or not'''
          # check that there is exactly 1 input
          if len(self.tx_ins) != 1:
              return False
          # grab the first input
          first_input = self.tx_ins[0]
          # check that first input prev_tx is b'\x00' * 32 bytes
          if first_input.prev_tx != b'\x00' * 32:
              return False
          # check that first input prev_index is 0xffffffff
          if first_input.prev_index != 0xffffffff:
              return False
          return True
  
      def coinbase_height(self):
          '''Returns the height of the block this coinbase transaction is in
          Returns None if this transaction is not a coinbase transaction
          '''
          # if this is NOT a coinbase transaction, return None
          if not self.is_coinbase():
              return None
          # grab the first input
          first_input = self.tx_ins[0]
          # grab the first element of the script_sig (.script_sig.items[0])
          first_element = first_input.script_sig.items[0]
          # convert the first element from little endian to int
          return little_endian_to_int(first_element)
  
  
  class TxIn:
  
      cache = {}
  
      def __init__(self, prev_tx, prev_index, script_sig, sequence):
          self.prev_tx = prev_tx
          self.prev_index = prev_index
          self.script_sig = script_sig
          self.sequence = sequence
  
      def __repr__(self):
          return '{}:{}'.format(
              self.prev_tx.hex(),
              self.prev_index,
          )
  
      @classmethod
      def parse(cls, s):
          '''Takes a byte stream and parses the tx_input at the start
          return a TxIn object
          '''
          # s.read(n) will return n bytes
          # prev_tx is 32 bytes, little endian
          prev_tx = s.read(32)[::-1]
          # prev_index is 4 bytes, little endian, interpret as int
          prev_index = little_endian_to_int(s.read(4))
          # script_sig is a variable field (length followed by the data)
          # you can use Script.parse to get the actual script
          script_sig = Script.parse(s)
          # sequence is 4 bytes, little-endian, interpret as int
          sequence = little_endian_to_int(s.read(4))
          # return an instance of the class (cls(...))
          return cls(prev_tx, prev_index, script_sig, sequence)
  
      def serialize(self):
          '''Returns the byte serialization of the transaction input'''
          # serialize prev_tx, little endian
          result = self.prev_tx[::-1]
          # serialize prev_index, 4 bytes, little endian
          result += int_to_little_endian(self.prev_index, 4)
          # serialize the script_sig
          result += self.script_sig.serialize()
          # serialize sequence, 4 bytes, little endian
          result += int_to_little_endian(self.sequence, 4)
          return result
  
      @classmethod
      def get_url(cls, testnet=False):
          if testnet:
              return 'http://tbtc.programmingblockchain.com:18332'
          else:
              return 'http://btc.programmingblockchain.com:8332'
  
      def fetch_tx(self, testnet=False):
          if self.prev_tx not in self.cache:
              url = '{}/rest/tx/{}.hex'.format(
                  self.get_url(testnet), self.prev_tx.hex())
              response = requests.get(url)
              raw = bytes.fromhex(response.text.strip())
              if raw[4] == 0:
                   # this is segwit, so convert to non-segwit
                  raw = raw[:4] + raw[6:]
              stream = BytesIO(raw)
              tx = Tx.parse(stream)
              self.cache[self.prev_tx] = tx
          return self.cache[self.prev_tx]
  
      def value(self, testnet=False):
          '''Get the outpoint value by looking up the tx hash
          Returns the amount in satoshi
          '''
          # use self.fetch_tx to get the transaction
          tx = self.fetch_tx(testnet=testnet)
          # get the output at self.prev_index
          # return the amount property
          return tx.tx_outs[self.prev_index].amount
  
      def script_pubkey(self, testnet=False):
          '''Get the scriptPubKey by looking up the tx hash
          Returns a Script object
          '''
          # use self.fetch_tx to get the transaction
          tx = self.fetch_tx(testnet=testnet)
          # get the output at self.prev_index
          # return the script_pubkey property
          return tx.tx_outs[self.prev_index].script_pubkey
  
      def der_signature(self):
          '''returns a DER format signature and hash_type if the script_sig
          has a signature'''
          signature = self.script_sig.signature()
          # last byte is the hash_type, rest is the signature
          return signature[:-1]
  
      def hash_type(self):
          '''returns a DER format signature and hash_type if the script_sig
          has a signature'''
          signature = self.script_sig.signature()
          # last byte is the hash_type, rest is the signature
          return signature[-1]
  
      def sec_pubkey(self):
          '''returns the SEC format public if the script_sig has one'''
          return self.script_sig.sec_pubkey()
  
  
  class TxOut:
  
      def __init__(self, amount, script_pubkey):
          self.amount = amount
          self.script_pubkey = script_pubkey
  
      def __repr__(self):
          return '{}:{}'.format(self.amount, self.script_pubkey)
  
      @classmethod
      def parse(cls, s):
          '''Takes a byte stream and parses the tx_output at the start
          return a TxOut object
          '''
          # s.read(n) will return n bytes
          # amount is 8 bytes, little endian, interpret as int
          amount = little_endian_to_int(s.read(8))
          # script_pubkey is a variable field (length followed by the data)
          # you can use Script.parse to get the actual script
          script_pubkey = Script.parse(s)
          # return an instance of the class (cls(...))
          return cls(amount, script_pubkey)
  
      def serialize(self):
          '''Returns the byte serialization of the transaction output'''
          # serialize amount, 8 bytes, little endian
          result = int_to_little_endian(self.amount, 8)
          # serialize the script_pubkey
          result += self.script_pubkey.serialize()
          return result
  
  
  class TxTest(TestCase):
  
      def test_parse_version(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertEqual(tx.version, 1)
  
      def test_parse_inputs(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertEqual(len(tx.tx_ins), 1)
          want = bytes.fromhex('d1c789a9c60383bf715f3f6ad9d14b91fe55f3deb369fe5d9280cb1a01793f81')
          self.assertEqual(tx.tx_ins[0].prev_tx, want)
          self.assertEqual(tx.tx_ins[0].prev_index, 0)
          want = bytes.fromhex('6b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278a')
          self.assertEqual(tx.tx_ins[0].script_sig.serialize(), want)
          self.assertEqual(tx.tx_ins[0].sequence, 0xfffffffe)
  
      def test_parse_outputs(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertEqual(len(tx.tx_outs), 2)
          want = 32454049
          self.assertEqual(tx.tx_outs[0].amount, want)
          want = bytes.fromhex('1976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac')
          self.assertEqual(tx.tx_outs[0].script_pubkey.serialize(), want)
          want = 10011545
          self.assertEqual(tx.tx_outs[1].amount, want)
          want = bytes.fromhex('1976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac')
          self.assertEqual(tx.tx_outs[1].script_pubkey.serialize(), want)
  
      def test_parse_locktime(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertEqual(tx.locktime, 410393)
  
      def test_der_signature(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          want = '3045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed'
          der = tx.tx_ins[0].der_signature()
          hash_type = tx.tx_ins[0].hash_type()
          self.assertEqual(der.hex(), want)
          self.assertEqual(hash_type, SIGHASH_ALL)
  
      def test_sec_pubkey(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          want = '0349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278a'
          self.assertEqual(tx.tx_ins[0].sec_pubkey().hex(), want)
  
      def test_serialize(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertEqual(tx.serialize(), raw_tx)
  
      def test_input_value(self):
          tx_hash = 'd1c789a9c60383bf715f3f6ad9d14b91fe55f3deb369fe5d9280cb1a01793f81'
          index = 0
          want = 42505594
          tx_in = TxIn(
              prev_tx=bytes.fromhex(tx_hash),
              prev_index=index,
              script_sig=Script([]),
              sequence=0,
          )
          self.assertEqual(tx_in.value(), want)
  
      def test_input_pubkey(self):
          tx_hash = 'd1c789a9c60383bf715f3f6ad9d14b91fe55f3deb369fe5d9280cb1a01793f81'
          index = 0
          tx_in = TxIn(
              prev_tx=bytes.fromhex(tx_hash),
              prev_index=index,
              script_sig=Script([]),
              sequence=0,
          )
          want = bytes.fromhex('1976a914a802fc56c704ce87c42d7c92eb75e7896bdc41ae88ac')
          self.assertEqual(tx_in.script_pubkey().serialize(), want)
  
      def test_fee(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertEqual(tx.fee(), 40000)
          raw_tx = bytes.fromhex('010000000456919960ac691763688d3d3bcea9ad6ecaf875df5339e148a1fc61c6ed7a069e010000006a47304402204585bcdef85e6b1c6af5c2669d4830ff86e42dd205c0e089bc2a821657e951c002201024a10366077f87d6bce1f7100ad8cfa8a064b39d4e8fe4ea13a7b71aa8180f012102f0da57e85eec2934a82a585ea337ce2f4998b50ae699dd79f5880e253dafafb7feffffffeb8f51f4038dc17e6313cf831d4f02281c2a468bde0fafd37f1bf882729e7fd3000000006a47304402207899531a52d59a6de200179928ca900254a36b8dff8bb75f5f5d71b1cdc26125022008b422690b8461cb52c3cc30330b23d574351872b7c361e9aae3649071c1a7160121035d5c93d9ac96881f19ba1f686f15f009ded7c62efe85a872e6a19b43c15a2937feffffff567bf40595119d1bb8a3037c356efd56170b64cbcc160fb028fa10704b45d775000000006a47304402204c7c7818424c7f7911da6cddc59655a70af1cb5eaf17c69dadbfc74ffa0b662f02207599e08bc8023693ad4e9527dc42c34210f7a7d1d1ddfc8492b654a11e7620a0012102158b46fbdff65d0172b7989aec8850aa0dae49abfb84c81ae6e5b251a58ace5cfeffffffd63a5e6c16e620f86f375925b21cabaf736c779f88fd04dcad51d26690f7f345010000006a47304402200633ea0d3314bea0d95b3cd8dadb2ef79ea8331ffe1e61f762c0f6daea0fabde022029f23b3e9c30f080446150b23852028751635dcee2be669c2a1686a4b5edf304012103ffd6f4a67e94aba353a00882e563ff2722eb4cff0ad6006e86ee20dfe7520d55feffffff0251430f00000000001976a914ab0c0b2e98b1ab6dbf67d4750b0a56244948a87988ac005a6202000000001976a9143c82d7df364eb6c75be8c80df2b3eda8db57397088ac46430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertEqual(tx.fee(), 140500)
  
      def test_sig_hash(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          hash_type = SIGHASH_ALL
          want = int('27e0c5994dec7824e56dec6b2fcb342eb7cdb0d0957c2fce9882f715e85d81a6', 16)
          self.assertEqual(tx.sig_hash(0, hash_type), want)
  
      def test_verify_input(self):
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertTrue(tx.verify_input(0))
  
      def test_sign_input(self):
          private_key = PrivateKey(secret=8675309)
          tx_ins = []
          prev_tx = bytes.fromhex('0025bc3c0fa8b7eb55b9437fdbd016870d18e0df0ace7bc9864efc38414147c8')
          tx_ins.append(TxIn(
              prev_tx=prev_tx,
              prev_index=0,
              script_sig=Script([]),
              sequence=0xffffffff,
          ))
          tx_outs = []
          h160 = decode_base58('mzx5YhAH9kNHtcN481u6WkjeHjYtVeKVh2')
          tx_outs.append(TxOut(amount=int(0.99 * 100000000), script_pubkey=p2pkh_script(h160)))
          h160 = decode_base58('mnrVtF8DWjMu839VW3rBfgYaAfKk8983Xf')
          tx_outs.append(TxOut(amount=int(0.1 * 100000000), script_pubkey=p2pkh_script(h160)))
  
          tx = Tx(
              version=1,
              tx_ins=tx_ins,
              tx_outs=tx_outs,
              locktime=0,
              testnet=True,
          )
          self.assertTrue(tx.sign_input(0, private_key, SIGHASH_ALL))
  
      def test_is_coinbase(self):
          raw_tx = bytes.fromhex('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff5e03d71b07254d696e656420627920416e74506f6f6c20626a31312f4542312f4144362f43205914293101fabe6d6d678e2c8c34afc36896e7d9402824ed38e856676ee94bfdb0c6c4bcd8b2e5666a0400000000000000c7270000a5e00e00ffffffff01faf20b58000000001976a914338c84849423992471bffb1a54a8d9b1d69dc28a88ac00000000')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertTrue(tx.is_coinbase())
  
      def test_coinbase_height(self):
          raw_tx = bytes.fromhex('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff5e03d71b07254d696e656420627920416e74506f6f6c20626a31312f4542312f4144362f43205914293101fabe6d6d678e2c8c34afc36896e7d9402824ed38e856676ee94bfdb0c6c4bcd8b2e5666a0400000000000000c7270000a5e00e00ffffffff01faf20b58000000001976a914338c84849423992471bffb1a54a8d9b1d69dc28a88ac00000000')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertEqual(tx.coinbase_height(), 465879)
          raw_tx = bytes.fromhex('0100000001813f79011acb80925dfe69b3def355fe914bd1d96a3f5f71bf8303c6a989c7d1000000006b483045022100ed81ff192e75a3fd2304004dcadb746fa5e24c5031ccfcf21320b0277457c98f02207a986d955c6e0cb35d446a89d3f56100f4d7f67801c31967743a9c8e10615bed01210349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278afeffffff02a135ef01000000001976a914bc3b654dca7e56b04dca18f2566cdaf02e8d9ada88ac99c39800000000001976a9141c4bc762dd5423e332166702cb75f40df79fea1288ac19430600')
          stream = BytesIO(raw_tx)
          tx = Tx.parse(stream)
          self.assertIsNone(tx.coinbase_height())
  