示例#1
0
 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 is an integer in 4 bytes, little-endian
     version = little_endian_to_int(s.read(4))
     # num_inputs is a varint, use read_varint(s)
     num_inputs = read_varint(s)
     # parse num_inputs number of TxIns
     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)
     # parse num_outputs number of TxOuts
     outputs = []
     for _ in range(num_outputs):
         outputs.append(TxOut.parse(s))
     # locktime is an integer in 4 bytes, little-endian
     locktime = little_endian_to_int(s.read(4))
     # return an instance of the class (see __init__ for args)
     return cls(version, inputs, outputs, locktime, testnet=testnet)
示例#2
0
 def test_varint(self):
     tests = [
         (0x01, unhexlify('01')),
         (0xfd, unhexlify('fdfd00')),
         (0xfe, unhexlify('fdfe00')),
         (0xff, unhexlify('fdff00')),
         (0x1234, unhexlify('fd3412')),
         (0x123456, unhexlify('fe56341200')),
         (0x123456789a01, unhexlify('ff019a785634120000')),
     ]
     for num, encoded in tests:
         self.assertEqual(encode_varint(num), encoded)
         s = BytesIO(encoded)
         self.assertEqual(read_varint(s), num)
     self.assertRaises(ValueError, encode_varint, 2**65)
示例#3
0
 def parse_segwit(cls, s, testnet=False):
     '''Takes a byte stream and parses a segwit transaction'''
     # s.read(n) will return n bytes
     # version has 4 bytes, little-endian, interpret as int
     version = little_endian_to_int(s.read(4))
     # next two bytes need to be 0x00 and 0x01, otherwise raise RuntimeError
     marker = s.read(2)
     if marker != b'\x00\x01':
         raise RuntimeError('Not a segwit transaction {}'.format(marker))
     # num_inputs is a varint, use read_varint(s)
     num_inputs = read_varint(s)
     # each input needs parsing, create inputs array
     inputs = []
     # parse each input and add to the inputs array
     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, create outputs array
     outputs = []
     # parse each output and add to the outputs array
     for _ in range(num_outputs):
         outputs.append(TxOut.parse(s))
     # there is a witness for each input
     for tx_in in inputs:
         # use Witness.parse to grab the witness
         tx_in.witness = Witness.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,
                segwit=True)
示例#4
0
 def parse_segwit(cls, s, testnet=False):
     '''Takes a byte stream and parses a segwit transaction'''
     # s.read(n) will return n bytes
     # version has 4 bytes, little-endian, interpret as int
     version = little_endian_to_int(s.read(4))
     # next two bytes need to be 0x00 and 0x01
     marker = s.read(2)
     if marker != b'\x00\x01':
         raise RuntimeError('Not a segwit transaction {}'.format(marker))
     # 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))
     # now parse the witness
     for tx_in in inputs:
         num_items = read_varint(s)
         items = []
         for _ in range(num_items):
             item_len = read_varint(s)
             if item_len == 0:
                 items.append(0)
             else:
                 items.append(s.read(item_len))
         tx_in.witness = items
     # 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, segwit=True)
示例#5
0
 def parse(cls, s):
     '''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))
     prev_block_hash = s.read(32)[::-1]
     # 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, prev_block_hash=prev_block_hash)
示例#6
0
 def parse(cls, s, coinbase_mode=False):
     # get the length of the entire field
     length = read_varint(s)
     if coinbase_mode:
         return cls([], coinbase=s.read(length))
     # initialize the instructions array
     instructions = []
     # initialize the number of bytes we've read to 0
     count = 0
     # loop until we've read length bytes
     while count < length:
         # get the current byte
         current = s.read(1)
         # increment the bytes we've read
         count += 1
         # convert the current byte to an integer
         current_byte = current[0]
         # if the current byte is between 1 and 75 inclusive
         if current_byte >= 1 and current_byte <= 75:
             # we have an instruction set n to be the current byte
             n = current_byte
             # add the next n bytes as an instruction
             instructions.append(s.read(n))
             # increase the count by n
             count += n
         elif current_byte == 76:
             # op_pushdata1
             data_length = little_endian_to_int(s.read(1))
             instructions.append(s.read(data_length))
             count += data_length + 1
         elif current_byte == 77:
             # op_pushdata2
             data_length = little_endian_to_int(s.read(2))
             instructions.append(s.read(data_length))
             count += data_length + 2
         elif current_byte == 78:
             # op_pushdata4
             data_length = little_endian_to_int(s.read(4))
             instructions.append(s.read(data_length))
             count += data_length + 4
         else:
             # we have an op code. set the current byte to op_code
             op_code = current_byte
             # add the op_code to the list of instructions
             instructions.append(op_code)
     if count != length:
         raise RuntimeError('parsing script failed')
     return cls(instructions)
示例#7
0
 def parse(cls, s):
     length = read_varint(s)
     items = []
     count = 0
     while count < length:
         current = s.read(1)
         count += 1
         current_byte = current[0]
         if current_byte >= 1 and current_byte <= 75:
             n = current_byte
             items.append(s.read(n))
             count += n
         else:
             op_code = current_byte
             items.append(op_code)
     return cls(items)
示例#8
0
 def parse(cls, s):
     # number of headers is in a varint
     num_headers = read_varint(s)
     # initialize the headers array
     headers = []
     # loop through number of headers times
     for _ in range(num_headers):
         # parse a header using Block.parse(s)
         header = Block.parse(s)
         # add the header to the headers array
         headers.append(header)
         # check that the length of the tx_hashes to be 0 or raise a RuntimeError
         if len(header.tx_hashes) != 0:
             raise RuntimeError('number of txs not 0')
     # return a class instance
     return cls(headers)
 def parse(cls, s):
     version = little_endian_to_int(s.read(4))
     prev_block = s.read(32)[::-1]
     merkle_root = s.read(32)[::-1]
     timestamp = little_endian_to_int(s.read(4))
     bits = s.read(4)
     nonce = s.read(4)
     num_tx = read_varint(s)
     txs = []
     for i in range(num_tx):
         if i == 0:
             txs.append(Tx.parse(s, coinbase_tx=True))
         else:
             txs.append(Tx.parse(s))
     return cls(version, prev_block, merkle_root, timestamp, bits, nonce,
                txs)
示例#10
0
 def parse(cls, s):
     '''Takes a byte stream and parses a merkle block. Returns a Merkle Block object'''
     # version - 4 bytes, Little-Endian integer
     header = Block.parse_header(s)
     # total transactions in block - 4 bytes, Little-Endian integer
     total = little_endian_to_int(s.read(4))
     # number of transaction hashes - varint
     num_txs = read_varint(s)
     # each transaction is 32 bytes, Little-Endian
     hashes = []
     for _ in range(num_txs):
         hashes.append(s.read(32)[::-1])
     # flags field - varstr
     flags = read_varstr(s)
     # initialize class
     return cls(header, total, hashes, flags)
示例#11
0
 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)
     # get the length by using read_varint(s)
     script_sig_length = read_varint(s)
     script_sig = s.read(script_sig_length)
     # 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)
示例#12
0
 def parse(cls, s):
     '''Takes a byte stream and parses the tx_output at the start
     return a TxOut object
     '''
     # amount is an integer in 8 bytes, little endian
     amount = little_endian_to_int(s.read(8))
     #scriptpublickey
     scritp_pubkey_length = read_varint(s)
     script_pubkey = s.read(scritp_pubkey_length)
     # use Script.parse to get the ScriptPubKey
     #try:
         #script_pubkey = Script.parse(s)
     #except:
         #print("BAD SCRIPT PUBLIC KEY.")
         #script_pubkey = Script()
     # return an instance of the class (see __init__ for args)
     return cls(amount, script_pubkey)
示例#13
0
 def test_exercise_10(self):
     block_hex = '0000000000044b01a9440b34f582fe171c7b8642fedd0ebfccf8fdf6a1810900'
     block_hash = bytes.fromhex(block_hex)
     node = SimpleNode('tbtc.programmingblockchain.com', testnet=True)
     node.handshake()
     getdata = GetDataMessage()
     getdata.add_data(BLOCK_DATA_TYPE, block_hash)
     node.send(getdata.command, getdata.serialize())
     block_envelope = node.wait_for_commands([b'block'])
     stream = block_envelope.stream()
     b = Block.parse(stream)
     self.assertTrue(b.check_pow())
     num_txs = read_varint(stream)
     tx_hashes = []
     for _ in range(num_txs):
         t = Tx.parse(stream)
         tx_hashes.append(t.hash())
     b.tx_hashes = tx_hashes
     self.assertTrue(b.validate_merkle_root())
示例#14
0
 def parse(cls, s):
     # get the length of the entire field
     length = read_varint(s)
     # initialize the cmds array
     cmds = []
     # initialize the number of bytes we've read to 0
     count = 0
     # loop until we've read length bytes
     while count < length:
         # get the current byte
         current = s.read(1)
         # increment the bytes we've read
         count += 1
         # convert the current byte to an integer
         current_byte = current[0]
         # if the current byte is between 1 and 75 inclusive
         if current_byte >= 1 and current_byte <= 75:
             # we have an cmd set n to be the current byte
             n = current_byte
             # add the next n bytes as an cmd
             cmds.append(s.read(n))
             # increase the count by n
             count += n
         elif current_byte == 76:
             # op_pushdata1
             data_length = little_endian_to_int(s.read(1))
             cmds.append(s.read(data_length))
             count += data_length + 1
         elif current_byte == 77:
             # op_pushdata2
             data_length = little_endian_to_int(s.read(2))
             cmds.append(s.read(data_length))
             count += data_length + 2
         else:
             # we have an opcode. set the current byte to op_code
             op_code = current_byte
             # add the op_code to the list of cmds
             cmds.append(op_code)
     if count != length:
         
         raise SyntaxError('parsing script failed')
     return cls(cmds)
示例#15
0
 def parse(cls, s):
     # script serialization always starts with the length of the script.
     length = read_varint(s)
     cmds = []
     count = 0
     # parse until whole script has been parsed.
     while count < length:
         # this byte's value determines if we have an opcode or an element.
         current = s.read(1)
         count += 1
         # this converts the current byte into an int.
         current_byte_as_int = current[0]
         print('curr byte', current_byte_as_int)
         # for a number between 1 and 75, we know the next n bytes are an element.
         if current_byte_as_int >= 1 and current_byte_as_int <= 75:
             n = current_byte_as_int
             # push the element into the stack.
             cmds.append(s.read(n))
             # update the count.
             count += n
         # 76 is OP_PUSHDATA1, so the next byte tells us how many bytes the next element is.
         elif current_byte_as_int == 76:
             # n is the number of bytes to read
             n = little_endian_to_int(s.read(1))
             # push the element into the stack.
             cmds.append(s.read(n))
             # update the count.
             count += n + 1
         # 77 is OP_PUSHDATA2, so the next 2 bytes tell us how many bytes the next element is.
         elif current_byte_as_int == 77:
             n = little_endian_to_int(s.read(2))
             cmds.append(s.read(n))
             count += n + 2
         # else we push the opcode onto the stack
         else:
             op_code = current_byte_as_int
             cmds.append(op_code)
     # script should have consumed exactly the number of bytes expected. If not we raise an error.
     print("count, length", count, length)
     if count != length:
         raise SyntaxError('Parsing script failed.')
     return cls(cmds)
示例#16
0
 async def process_queue(self):
     print("start processing")
     start = time.time()
     while self.keep_looping:
         envelope = await self.q.get()
         command = envelope.command.strip(b'\x00').decode('ascii')
         if command == 'version':
             self.send(b'verack', b'')
         elif command == 'sendheaders':
             self.send(b'headers', encode_varint(0))
         elif command == 'ping':
             self.send(b'pong', envelope.payload)
             if not self._sent:
                 # tell them we have a tx
                 self.send(b'inv', self.inv_payload)
             elif not self._accepted:
                 self.send(b'tx', self.raw_tx)
             self.send(b'mempool', b'')
         elif command == 'getdata':
             if envelope.payload == self.inv_payload:
                 self.send(b'tx', self.raw_tx)
                 self._sent = True
             elif self._sent:
                 print('TX rejected')
                 self.keep_looping = False
         elif command == 'feefilter':
             minimum = little_endian_to_int(envelope.payload)
             print('TX requires fee: {} minimum'.format(minimum))
         elif command == 'inv':
             stream = BytesIO(envelope.payload)
             num_inv = read_varint(stream)
             for _ in range(num_inv):
                 inv_type = little_endian_to_int(stream.read(4))
                 inv_hash = stream.read(32)
                 if inv_type == 1 and inv_hash == self.tx_hash:
                     print('TX successfully sent')
                     self.keep_looping = False
             self.send(b'inv', self.inv_payload)
         else:
             print(envelope)
         if time.time() - start < self.timeout:
             self.keep_looping = False
示例#17
0
 def save(self):
     store_height = self.store_height()
     if exists(self.filename):
         with open(self.filename, 'rb') as f:
             file_height = read_varint(f)
             if store_height == file_height:
                 # no need to save as we're synced
                 return
             rest = f.read()
     else:
         file_height = -1
         rest = b''
     with open(self.filename, 'wb') as f:
         f.write(encode_varint(store_height))
         for height in range(store_height, file_height, -1):
             h = self.header_by_height(height)
             f.write(h.serialize())
             f.write(h.cfheader)
             f.write(h.cfhash)
         f.write(rest)
示例#18
0
 def parse(cls, s):
     '''Takes a byte stream and parses a block. Returns a BlockHeader object'''
     # s.read(n) will read n bytes from the stream
     # version - 4 bytes, little endian, interpret as int
     version = little_endian_to_int(s.read(4))
     # prev_block - 32 bytes, little endian (use [::-1] to reverse)
     prev_block = s.read(32)[::-1]
     # merkle_root - 32 bytes, little endian (use [::-1] to reverse)
     merkle_root = s.read(32)[::-1]
     # timestamp - 4 bytes, little endian, interpret as int
     timestamp = little_endian_to_int(s.read(4))
     # bits - 4 bytes
     bits = s.read(4)
     # nonce - 4 bytes
     nonce = s.read(4)
     # read the actual transactions
     num_txns = read_varint(s)
     txns = [Tx.parse(s) for _ in range(num_txns)]
     # initialize class
     return cls(version, prev_block, merkle_root, timestamp, bits, nonce,
                txns)
示例#19
0
 def __init__(self, node, filename=None, full=False, include=None):
     self.node = node
     self.testnet = node.testnet
     if filename is None:
         if self.testnet:
             self.filename = 'testnet.blocks'
         else:
             self.filename = 'mainnet.blocks'
     else:
         self.filename = filename
     self.full = full
     self.include = include
     self.start_height = 0
     if not exists(self.filename):
         # new store
         # start from the genesis block
         if self.testnet:
             header = TESTNET_GENESIS_BLOCK_HEADER
         else:
             header = GENESIS_BLOCK_HEADER
         self.headers = [Block.parse_header(BytesIO(header))]
     else:
         with open(self.filename, 'rb') as f:
             headers = []
             file_height = read_varint(f)
             if self.full:
                 self.start_height = 0
             elif self.include and self.include < file_height:
                 # start of difficulty adjustment that includes this block
                 self.start_height = (self.include // 2016) * 2016
             else:
                 # one full difficulty adjustment + remaining
                 self.start_height = (file_height // 2016 - 1) * 2016
             for _ in range(self.start_height, file_height + 1):
                 header = Block.parse_header(f)
                 header.cfheader = f.read(32)
                 header.cfhash = f.read(32)
                 headers.append(header)
             self.headers = headers[::-1]
     self.headers_lookup = {h.hash(): h for h in self.headers}
示例#20
0
 def parse_from_blk(cls, s):
     '''Takes a byte stream and parses a block. Returns a Block object'''
     # s.read(n) will read n bytes from the stream
     magic = little_endian_to_int(s.read(4))
     size = little_endian_to_int(s.read(4))
     # version - 4 bytes, little endian, interpret as int
     version = little_endian_to_int(s.read(4))
     # prev_block - 32 bytes, little endian (use [::-1] to reverse)
     prev_block = s.read(32)[::-1]
     # merkle_root - 32 bytes, little endian (use [::-1] to reverse)
     merkle_root = s.read(32)[::-1]
     # timestamp - 4 bytes, little endian, interpret as int
     timestamp = little_endian_to_int(s.read(4))
     # bits - 4 bytes
     bits = s.read(4)
     # nonce - 4 bytes
     nonce = s.read(4)
     #THIS IS ADDED AT THE END.
     tx_hashes = read_varint(s)
     # initialize class
     return cls(version, prev_block, merkle_root, timestamp, bits, nonce,
                tx_hashes, magic, size)
示例#21
0
 def parse(cls, s):
     '''Takes a byte stream and parses the tx_input at the start
     return a TxIn object
     '''
     # prev_tx is 32 bytes, little endian
     prev_tx = s.read(32)[::-1]
     # prev_index is an integer in 4 bytes, little endian
     prev_index = little_endian_to_int(s.read(4))
     #read the script sig and convert it to hex
     sig_length = read_varint(s)
     script_sig = s.read(sig_length)
     #script_sig = script_sig.hex()
     # use Script.parse to get the ScriptSig
     #try:
         #script_sig = Script.parse(s)
     #except:
         #print(f"BAD SCRIPT SIGNATURE")
         #script_sig = Script()
     # sequence is an integer in 4 bytes, little-endian
     sequence = little_endian_to_int(s.read(4))
     # return an instance of the class (see __init__ for args)
     return cls(prev_tx, prev_index, script_sig, sequence)
示例#22
0
 def parse(cls, s: BufferedIOBase) -> Script:
     # get the length of the entire field
     length = read_varint(s)
     # initialize the commands array
     commands = []
     # initialize the number of bytes we've read to 0
     count = 0
     # loop until we've read length bytes
     while count < length:
         # get the current byte
         current = s.read(1)
         # increment the bytes we've read
         count += 1
         # convert the current byte to an integer
         current_int = current[0]
         # if the current byte is between 1 and 75 inclusive
         if current_int <= 75:
             # add the next n bytes as a command
             commands.append(s.read(current_int))
             count += current_int
         elif current == OP_PUSHDATA1:
             # op_pushdata1
             data_length = byte_to_int(s.read(1))
             commands.append(s.read(data_length))
             count += data_length + 1
         elif current == OP_PUSHDATA2:
             # op_pushdata2
             data_length = little_endian_to_int(s.read(2))
             commands.append(s.read(data_length))
             count += data_length + 2
         else:
             # add the command to the list of commands
             commands.append(current)
     if count != length:
         raise SyntaxError(f'parsing script failed {commands}')
     return cls(commands)
示例#23
0
 def parse(cls, s):
     salt = s.read(32)
     data_len = read_varint(s)
     encrypted_data = s.read(data_len)
     return cls(salt, encrypted_data)
示例#24
0
 def parse(cls, stream):
     count = read_varint(stream)
     address_list = []
     for _ in range(count):
         address_list.append(Address.parse(stream))
     return cls(address_list)
示例#25
0
def read_varstr(s):
    item_length = read_varint(s)
    return s.read(item_length)
示例#26
0
    def parse(cls, s):
        # get the length of the entire field
        #print(s)
        length = read_varint(s)
        #print(f"length script: {length}")
        # initialize the cmds array
        cmds = []
        # initialize the number of bytes we've read to 0
        count = 0
        # loop until we've read length bytes
        while count < length:
            # get the current byte
            #print(f"WHILE: count {count} and length {length}")
            current = s.read(1)
            # increment the bytes we've read
            count += 1
            # convert the current byte to an integer
            current_byte = current[0]
            #print(f"current_byte : {current_byte}")
            # if the current byte is between 1 and 75 inclusive
            if current_byte >= 1 and current_byte <= 75:
                # we have an cmd set n to be the current byte
                n = current_byte
                # add the next n bytes as an cmd
                cmds.append(s.read(n))
                # increase the count by n
                count += n
            elif current_byte == 76:
                # op_pushdata1
                data_length = little_endian_to_int(s.read(1))

                if (data_length + count) > length:
                    print(
                        f"BAD SCRIPT: original script data_length {data_length} "
                    )
                    data_length = length - count - 1
                    print(f"Fixed script data_length to {data_length }")
                    s.read(data_length)
                    raise SyntaxError('parsing script failed')

                cmds.append(s.read(data_length))
                count += data_length + 1
            elif current_byte == 77:
                # op_pushdata2
                data_length = little_endian_to_int(s.read(2))

                if (data_length + count) > length:
                    print(
                        f"BAD SCRIPT: original script data_length {data_length} "
                    )
                    data_length = length - count - 2
                    print(f"Fixed script data_length to {data_length}")
                    s.read(data_length)
                    raise SyntaxError('parsing script failed')

                cmds.append(s.read(data_length))
                count += data_length + 2
            else:
                # we have an opcode. set the current byte to op_code
                op_code = current_byte
                #print(f"op_code : {op_code}")
                # add the op_code to the list of cmds
                cmds.append(op_code)
        if count != length:
            raise SyntaxError('parsing script failed')
        return cls(cmds)