開発環境
- macOS Mojave - Apple (OS)
- Emacs (Text Editor)
- Windows 10 Pro (OS)
- Visual Studio Code (Text Editor)
- Python 3.7 (プログラミング言語)
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 コメント:
コメントを投稿