2019年4月25日木曜日

開発環境

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

コード

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 = '0100000004'
        b = io.BytesIO(bytes.fromhex(hex_transaction))
        parsed = Transaction.parse(b)
        self.assertEqual(1, parsed.version)
        self.assertEqual(4, len(parsed.tx_ins))

        hex_transaction = '01000000fd0400'
        b = io.BytesIO(bytes.fromhex(hex_transaction))
        parsed = Transaction.parse(b)
        self.assertEqual(1, parsed.version)
        self.assertEqual(4, len(parsed.tx_ins))

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

        hex_transaction = '01000000ff0001000000000000'
        b = io.BytesIO(bytes.fromhex(hex_transaction))
        parsed = Transaction.parse(b)
        self.assertEqual(1, parsed.version)
        self.assertEqual(256, len(parsed.tx_ins))


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

    def tearDown(self):
        pass


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

    @classmethod
    def parse(cls, stream):
        version = little_endian_to_int(stream.read(4))
        inputs = [TransactionInput.parse(stream)
                  for _ in range(read_varint(stream))]
        return cls(version, inputs, None, None)


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)


if __name__ == '__main__':
    main()

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

C:\Users\...>py sample2.py
E
======================================================================
ERROR: test_parse (__main__.TransactionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "sample2.py", line 18, in test_parse
    self.assertEqual(4, len(parsed.tx_ins))
TypeError: object of type 'NoneType' has no len()

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

FAILED (errors=1)

C:\Users\...>py sample2.py
E
======================================================================
ERROR: test_parse (__main__.TransactionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "sample2.py", line 16, in test_parse
    parsed = Transaction.parse(b)
  File "sample2.py", line 50, in parse
    for _ in range(read_varint(stream))]
  File "sample2.py", line 50, in <listcomp>
    for _ in range(read_varint(stream))]
AttributeError: type object 'TransactionInput' has no attribute 'parse'

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

FAILED (errors=1)

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

OK

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

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

OK

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

OK

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

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

OK

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

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

OK

C:\Users\...>py sample2.py -v
test_parse (__main__.TransactionTest) ... FAIL

======================================================================
FAIL: test_parse (__main__.TransactionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "sample2.py", line 36, in test_parse
    self.assertEqual(16, len(parsed.tx_ins))
AssertionError: 16 != 4

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

C:\Users\...>py sample2.py -v
test_parse (__main__.TransactionTest) ... FAIL

======================================================================
FAIL: test_parse (__main__.TransactionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "sample2.py", line 36, in test_parse
    self.assertEqual(16, len(parsed.tx_ins))
AssertionError: 16 != 256

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

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

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

C:\Users\...>

0 コメント:

コメントを投稿