예제 #1
0
def unwrap_network_message(data):
    datacpy = data

    if len(data) < 24:
        return None, None, None, data

    magic, data = read_bytes(data, 4, int, 'little')
    assert magic == Constants.NETWORK_MAGIC

    cmd, data = read_bytes(data, 12, bytes, 'big')

    i = 0
    while cmd[i] != 0 and i < 12:
        i += 1
    try:
        command = cmd[:i].decode('ascii')
    except UnicodeDecodeError:
        raise NetworkError("Invalid command encoding")
    except Exception as e:
        print(e)

    length, data = read_bytes(data, 4, int, 'little')
    if (len(data) - 4) < length:
        return command, None, length, datacpy

    checksum, data = read_bytes(data, 4, bytes, 'big')
    payload, data = read_bytes(data, length, bytes, 'big')
    assert checksum == dsha256(payload)[:4]

    return command, payload, length, data
예제 #2
0
def parse_unlocking_script(script):
    # Returns type, signatures, public keys and address of the input
    if len(script) in [71, 72, 73]:
        # Pay-to-Public-Key: the unlocking script is the signature
        sig, script = read_data(script)
        assert script == bytes()
        return "p2pk", [sig], None, None, None
    elif len(script) in [105, 106, 107, 137, 138, 139]:  #P2PKH
        # Pay-to-Public-Key-Hash: signature and public key
        sig, script = read_data(script)
        pubkey, script = read_data(script)
        assert script == bytes()
        return "p2pkh", [sig], [PublicKey.from_ser(pubkey)
                                ], Address.from_pubkey(pubkey), None
    elif script[0] == OP_0:
        # P2SH multisig
        zero, script = read_bytes(script, 1, int, 'little')
        data = []
        while script != bytes():
            d, script = read_data(script)
            data.append(d)
        signatures, redeemScript = data[:-1], data[-1]

        # Address
        address = Address.from_script(redeemScript)

        rs = redeemScript
        # Parsing of redeem script
        m, rs = read_bytes(rs, 1, int, 'little')
        assert len(signatures) == (m - OP_1 +
                                   1), "m = {:d}, len sigs = {:d}".format(
                                       m, len(signatures))
        pubkeys = []
        while 0 < rs[0] <= OP_PUSHDATA4:
            pubkey, rs = read_data(rs)
            pubkeys.append(PublicKey.from_ser(pubkey))
        n, rs = read_bytes(rs, 1, int, 'little')
        assert len(pubkeys) == (n - OP_1 + 1)
        assert rs[0] == OP_CHECKMULTISIG

        return "p2sh", signatures, pubkeys, address, redeemScript
    else:
        raise ScriptError("cannot parse unlocking script")
예제 #3
0
    def recv_inv(self, payload):
        count, payload = read_var_int(payload)

        for i in range(count):
            data, payload = read_bytes(payload, 36, bytes, 'big')
            inv = InventoryVector.from_serialized(data)
            # TODO get data if we need it
            #   invs.append( inv )
            # self.send_getdata( invs )
            print(inv)
예제 #4
0
def read_nulldata_script(script):
    ''' Read nulldata script content. '''
    assert len(script) <= 223
    ret, script = read_bytes(script, 1, int, 'big')
    assert ret == OP_RETURN

    data = []
    while script != bytes():
        d, script = read_data(script)
        data.append(d)
    return data
예제 #5
0
    def recv_reject(self, payload):
        length_msg, payload = read_var_int(payload)
        raw_msg, payload = read_bytes(payload, length_msg, bytes, 'big')
        msg = raw_msg.decode('ascii')
        ccode, payload = read_bytes(payload, 1, int, 'little')
        length_reason, payload = read_var_int(payload)
        raw_reason, payload = read_bytes(payload, length_reason, bytes, 'big')
        reason = raw_reason.decode('utf-8')
        data = payload.hex()

        print("{} reject {}: {}, {} {}".format(
            self.address['host'], msg, {
                Constants.REJECT_MALFORMED: "malformed",
                Constants.REJECT_INVALID: "invalid",
                Constants.REJECT_OBSOLETE: "obsolete",
                Constants.REJECT_DUPLICATE: "duplicate",
                Constants.REJECT_NONSTANDARD: "non standard",
                Constants.REJECT_DUST: "dust",
                Constants.REJECT_INSUFFICIENTFEE: "insufficient fee",
                Constants.REJECT_CHECKPOINT: "checkpoint"
            }[ccode], reason, data))
예제 #6
0
    def recv_headers(self, payload):
        count, payload = read_var_int(payload)
        assert count <= 2000

        headers = []
        for i in range(count):
            hdr, payload = read_bytes(payload, Constants.BLOCKHEADER_SIZE,
                                      bytes, 'big')
            headers.append(hdr)
            tx_count, payload = read_var_int(payload)
            assert tx_count == 0

        self.network.received_headers(self, headers)
예제 #7
0
    def recv_getdata(self, payload):
        count, payload = read_var_int(payload)

        for i in range(count):
            data, payload = read_bytes(payload, 36, bytes, 'big')
            inv = InventoryVector.from_serialized(data)
            if inv in self.inventory:
                if inv.is_tx():
                    try:
                        tx = self.txdb[inv.get_id()]
                    except:
                        raise NetworkError("cannot retrieve transaction")
                    else:
                        self.send_tx(bytes.fromhex(tx))
예제 #8
0
def deserialize_network_address(data, with_timestamp=True):
    if with_timestamp and len(data) != 30:
        print("Network address should be 30-byte long")
        raise NetworkError("Network address should be 30-byte long")
    elif not with_timestamp and len(data) != 26:
        print("Network address should be 26-byte long")
        raise NetworkError("Network address should be 26-byte long")

    netaddr = {}
    if with_timestamp:
        netaddr['time'], data = read_bytes(data, 4, int, 'little')

    netaddr['services'], data = read_bytes(data, 8, int, 'little')
    address, data = read_bytes(data, 16, bytes, 'big')
    if address[0:-4] == bytes([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff]):
        # IPv4
        netaddr['host'] = socket.inet_ntop(socket.AF_INET, address[-4:])
    else:
        # IPv6
        netaddr['host'] = socket.inet_ntop(socket.AF_INET6, address)
    netaddr['port'], data = read_bytes(data, 2, int, 'big')

    return netaddr
예제 #9
0
    def recv_version(self, payload):
        if len(payload) < 20:
            self.state = 'dead'
            return

        try:
            self.version, payload = read_bytes(payload, 4, int, 'little')
            self.services, payload = read_bytes(payload, 8, int, 'little')
            self.time, payload = read_bytes(payload, 8, int, 'little')
            addr_recv, payload = read_bytes(payload, 26, bytes, 'big')
            my_network_address = deserialize_network_address(
                addr_recv, with_timestamp=False)
            addr_trans, payload = read_bytes(payload, 26, bytes, 'big')
            peer_network_address = deserialize_network_address(
                addr_trans, with_timestamp=False)
            nonce, payload = read_bytes(payload, 8, int, 'little')
            peer_user_agent_size, payload = read_var_int(payload)
            peer_user_agent, payload = read_bytes(payload,
                                                  peer_user_agent_size, bytes,
                                                  'big')
            self.block_height, payload = read_bytes(payload, 4, int, 'little')
            relay, payload = read_bytes(payload, 1, int, 'little')
            assert payload == bytes()
        except:
            self.state = 'dead'
            return

        print(" Peer address: {}\n Services: {:d}\n User Agent: {}".format(
            peer_network_address['host'], peer_network_address['services'],
            peer_user_agent.decode('ascii')))

        self.send_verack()
        self.peer_verack += 1

        if not self.sent_version:
            self.send_version()

        if self.peer_verack == 2:
            self.handshake_time = time.time()
            print("{} handshake done".format(self.address['host']))
예제 #10
0
    def recv_addr(self, payload):
        count, payload = read_var_int(payload)

        for i in range(count):
            data, payload = read_bytes(payload, 30, bytes, 'big')
            address = deserialize_network_address(data, with_timestamp=True)

            if not any([
                    address['host'] == na['host']
                    for na in self.network.peer_list
            ]) & (address['host'] !=
                  "") & (address['port'] == Constants.DEFAULT_PORT) & (
                      len(self.network.peer_list) <
                      self.network.MAX_PEER_ADDRESSES):
                self.network.peer_list.append(address)
                print("New peer address: {}".format(address['host']))
        assert payload == bytes()
예제 #11
0
def decode_xkey(xkey):
    payload = Base58.decode_check(xkey)
    assert len(payload) == 78
    header, payload = read_bytes(payload, 4, int, 'big')
    depth, payload = read_bytes(payload, 1, int, 'big')
    fingerprint, payload = read_bytes(payload, 4, bytes, 'big')
    child_number, payload = read_bytes(payload, 4, bytes, 'big')
    chain_code, payload = read_bytes(payload, 32, bytes, 'big')

    if header == Constants.XPRV_HEADER:
        dummy, payload = read_bytes(payload, 1, int, 'big')
        assert dummy == 0
        key, payload = read_bytes(payload, 32, bytes, 'big')
    elif header == Constants.XPUB_HEADER:
        key, payload = read_bytes(payload, 33, bytes, 'big')
    else:
        raise KeyDerivationError('Invalid extended key format')
    assert payload == bytes()
    return key, chain_code, depth, fingerprint, child_number
예제 #12
0
    def from_serialized(self, raw):
        assert isinstance(raw, bytes)
        self.raw = raw
        version, raw = read_bytes(raw, 4, int, 'little')

        input_count, raw = read_var_int(raw)
        txins = []
        for i in range(input_count):
            txin = {}
            txin['txid'], raw = read_bytes(raw, 32, hex, 'little')
            txin['index'], raw = read_bytes(raw, 4, int, 'little')
            scriptsize, raw = read_var_int(raw)
            unlockingScript, raw = read_bytes(raw, scriptsize, bytes, 'big')
            txin['unlocking_script'] = unlockingScript.hex()
            if (txin['txid'] == "00" * 32) & (txin['index'] == 0xffffffff):
                # Coinbase input
                txin['type'] = "coinbase"
            else:
                t, signatures, pubkeys, address, redeem_script = parse_unlocking_script(
                    unlockingScript)
                txin['type'] = t
                if t == "p2pk":
                    txin['signatures'] = [sig.hex() for sig in signatures]
                elif t == "p2pkh":
                    txin['signatures'] = [sig.hex() for sig in signatures]
                    txin['pubkeys'] = pubkeys
                    txin['address'] = address
                elif t == "p2sh":
                    # only p2sh-ms for the moment
                    txin['signatures'] = [sig.hex() for sig in signatures]
                    txin['pubkeys'] = pubkeys
                    txin['address'] = address
                    txin['redeem_script'] = redeem_script
                elif t == "p2ms":
                    raise TransactionError("we do not parse p2ms outputs")
                else:
                    raise TransactionError("cannot parse unlocking script")
                txin['nsigs'] = len(signatures)
            txin['sequence'], raw = read_bytes(raw, 4, int, 'little')
            txins.append(txin)

        output_count, raw = read_var_int(raw)
        txouts = []
        for i in range(output_count):
            txout = {}
            txout['value'], raw = read_bytes(raw, 8, int, 'little')
            scriptsize, raw = read_var_int(raw)
            lockingScript, raw = read_bytes(raw, scriptsize, bytes, 'big')
            txout['locking_script'] = lockingScript.hex()
            t, address, data = parse_locking_script(lockingScript)
            txout['type'] = t
            if t in ("p2pkh", "p2sh"):
                txout['address'] = address
            elif t == "p2pk":
                txout['address'] = address
            elif t == "nulldata":
                txout['data'] = data
            elif t == "p2ms":
                raise TransactionError("we do not parse p2pk and p2ms outputs")
            else:
                raise TransactionError("cannot parse unlocking script")
            txouts.append(txout)

        locktime, raw = read_bytes(raw, 4, int, 'little')

        return self(version, txins, txouts, locktime)
예제 #13
0
 def recv_feefilter(self, payload):
     self.peer_feerate, payload = read_bytes(payload, 8, int, 'little')
     print("feerate (sat/kB)", self.peer_feerate)