2019年9月2日月曜日

開発環境

Programming Bitcoin: Learn How to Program Bitcoin from Scratch (Jimmy Song(著)、O'Reilly Media)のChapter 5(Transactions)、Transaction Fee、Exercises 6(102)の解答を求めてみる。

コード

Python 3

#!/usr/bin/env python3
from unittest import TestCase, main


class TransactionTest(TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_parse(self):
        import io
        hex_transaction = '01000000' + \
            '01' + \
            '11223344556677889900' + \
            '11223344556677889900' + \
            '11223344556677889900' + \
            '1122' + \
            '11223344' + \
            '11223344' + \
            '01' + \
            '1122334455667788' + \
            '10000000'

        b = io.BytesIO(bytes.fromhex(hex_transaction))
        parsed = Transaction.parse(b)
        self.assertEqual(1, parsed.version)
        self.assertEqual(1, len(parsed.tx_ins))
        self.assertEqual(1, len(parsed.tx_outs))
        self.assertEqual(16, parsed.locktime)


def little_endian_to_int(b: bytes) -> int:
    return int.from_bytes(b, 'little')


def read_varint(s):
    i = s.read(1)[0]
    d = {0xfd: 2, 0xfe: 4, 0xff: 8}
    if i in d:
        return little_endian_to_int(s.read(d[i]))
    return i


class Transaction:
    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

    @classmethod
    def parse(cls, stream):
        version = little_endian_to_int(stream.read(4))
        inputs = [TransactionInput.parse(stream)
                  for _ in range(read_varint(stream))]
        outputs = [TransactionOutput.parse(stream)
                   for _ in range(read_varint(stream))]
        locktime = int.from_bytes(stream.read(4), 'little')
        return cls(version, inputs, outputs, locktime)

    def fee(self, testnet=False):
        return sum([tx_in.value() for tx_in in self.tx_ins]) - \
            sum([tx_out.value() for tx_out in self.tx_outs])


class TransactionInput:
    def __init__(
            self, prev_tx, prev_index, script_sig=None, sequence=0xffffffff):
        pass

    def __repr__(self):
        return f'{self.prev_tx.hex()}:{self.prev_index}'

    @classmethod
    def parse(cls, stream):
        tx_id = stream.read(32)
        prev_index = stream.read(4)
        # script_sig = Script.parse(s)
        sequence = stream.read(4)
        return cls(tx_id, prev_index, None, sequence)

    def value(self, testnet=False):
        pass


class TransactionOutput:
    def __init__(self, amount, script_pubkey):
        pass

    def __repr__(self):
        return f'{self.amount}:{self.script_pubkey}'

    @classmethod
    def parse(cls, stream):
        amount = stream.read(8)
        # script_pubkey = Script.parse(s)
        return cls(amount, None)

    def value(self, testnet=False):
        pass


if __name__ == '__main__':
    main()

入出力結果(Bash、cmd.exe(コマンドプロンプト)、Terminal、Jupyter(IPython))

$ mypy sample6.py
$ ./sample6.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
$ 

0 コメント:

コメントを投稿