2019年4月27日土曜日

開発環境

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

コード

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)


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)


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)


if __name__ == '__main__':
    main()

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

C:\Users\...>py sample3.py
C:\Users\...>py sample4.py
E
======================================================================
ERROR: test_parse (__main__.TransactionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "sample4.py", line 30, in test_parse
    self.assertEqual(16, parsed.locktime)
AttributeError: 'Transaction' object has no attribute 'locktime'

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

C:\Users\...>py sample4.py
F
======================================================================
FAIL: test_parse (__main__.TransactionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "sample4.py", line 30, in test_parse
    self.assertEqual(16, parsed.locktime)
AssertionError: 16 != None

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

C:\Users\...>py sample4.py
F
======================================================================
FAIL: test_parse (__main__.TransactionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "sample4.py", line 30, in test_parse
    self.assertEqual(16, parsed.locktime)
AssertionError: 16 != 0

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

C:\Users\...>py sample4.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

C:\Users\...>py sample4.py -v
test_parse (__main__.TransactionTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

C:\Users\...>

0 コメント:

コメントを投稿