Skip to content

Commit 1b035c0

Browse files
committed
refactor: move PSBT(Map) helpers from signet miner to test framework
Can be easily reviewed with `--color-moved=dimmed-zebra`.
1 parent 7c0dfec commit 1b035c0

File tree

2 files changed

+82
-72
lines changed

2 files changed

+82
-72
lines changed

contrib/signet/miner

Lines changed: 2 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

66
import argparse
7-
import base64
87
import json
98
import logging
109
import math
@@ -20,7 +19,8 @@ PATH_BASE_TEST_FUNCTIONAL = os.path.abspath(os.path.join(PATH_BASE_CONTRIB_SIGNE
2019
sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL)
2120

2221
from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height # noqa: E402
23-
from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, deser_string, ser_compact_size, ser_string, ser_uint256, tx_from_hex # noqa: E402
22+
from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, ser_string, ser_uint256, tx_from_hex # noqa: E402
23+
from test_framework.psbt import PSBT, PSBTMap # noqa: E402
2424
from test_framework.script import CScriptOp # noqa: E402
2525

2626
logging.basicConfig(
@@ -32,76 +32,6 @@ SIGNET_HEADER = b"\xec\xc7\xda\xa2"
3232
PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed
3333
RE_MULTIMINER = re.compile("^(\d+)(-(\d+))?/(\d+)$")
3434

35-
# #### some helpers that could go into test_framework
36-
37-
class PSBTMap:
38-
"""Class for serializing and deserializing PSBT maps"""
39-
40-
def __init__(self, map=None):
41-
self.map = map if map is not None else {}
42-
43-
def deserialize(self, f):
44-
m = {}
45-
while True:
46-
k = deser_string(f)
47-
if len(k) == 0:
48-
break
49-
v = deser_string(f)
50-
if len(k) == 1:
51-
k = k[0]
52-
assert k not in m
53-
m[k] = v
54-
self.map = m
55-
56-
def serialize(self):
57-
m = b""
58-
for k,v in self.map.items():
59-
if isinstance(k, int) and 0 <= k and k <= 255:
60-
k = bytes([k])
61-
m += ser_compact_size(len(k)) + k
62-
m += ser_compact_size(len(v)) + v
63-
m += b"\x00"
64-
return m
65-
66-
class PSBT:
67-
"""Class for serializing and deserializing PSBTs"""
68-
69-
def __init__(self):
70-
self.g = PSBTMap()
71-
self.i = []
72-
self.o = []
73-
self.tx = None
74-
75-
def deserialize(self, f):
76-
assert f.read(5) == b"psbt\xff"
77-
self.g = from_binary(PSBTMap, f)
78-
assert 0 in self.g.map
79-
self.tx = from_binary(CTransaction, self.g.map[0])
80-
self.i = [from_binary(PSBTMap, f) for _ in self.tx.vin]
81-
self.o = [from_binary(PSBTMap, f) for _ in self.tx.vout]
82-
return self
83-
84-
def serialize(self):
85-
assert isinstance(self.g, PSBTMap)
86-
assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
87-
assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
88-
assert 0 in self.g.map
89-
tx = from_binary(CTransaction, self.g.map[0])
90-
assert len(tx.vin) == len(self.i)
91-
assert len(tx.vout) == len(self.o)
92-
93-
psbt = [x.serialize() for x in [self.g] + self.i + self.o]
94-
return b"psbt\xff" + b"".join(psbt)
95-
96-
def to_base64(self):
97-
return base64.b64encode(self.serialize()).decode("utf8")
98-
99-
@classmethod
100-
def from_base64(cls, b64psbt):
101-
return from_binary(cls, base64.b64decode(b64psbt))
102-
103-
# #####
104-
10535
def create_coinbase(height, value, spk):
10636
cb = CTransaction()
10737
cb.vin = [CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff)]
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2022 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
import base64
7+
8+
from .messages import (
9+
CTransaction,
10+
deser_string,
11+
from_binary,
12+
ser_compact_size,
13+
)
14+
15+
16+
class PSBTMap:
17+
"""Class for serializing and deserializing PSBT maps"""
18+
19+
def __init__(self, map=None):
20+
self.map = map if map is not None else {}
21+
22+
def deserialize(self, f):
23+
m = {}
24+
while True:
25+
k = deser_string(f)
26+
if len(k) == 0:
27+
break
28+
v = deser_string(f)
29+
if len(k) == 1:
30+
k = k[0]
31+
assert k not in m
32+
m[k] = v
33+
self.map = m
34+
35+
def serialize(self):
36+
m = b""
37+
for k,v in self.map.items():
38+
if isinstance(k, int) and 0 <= k and k <= 255:
39+
k = bytes([k])
40+
m += ser_compact_size(len(k)) + k
41+
m += ser_compact_size(len(v)) + v
42+
m += b"\x00"
43+
return m
44+
45+
class PSBT:
46+
"""Class for serializing and deserializing PSBTs"""
47+
48+
def __init__(self):
49+
self.g = PSBTMap()
50+
self.i = []
51+
self.o = []
52+
self.tx = None
53+
54+
def deserialize(self, f):
55+
assert f.read(5) == b"psbt\xff"
56+
self.g = from_binary(PSBTMap, f)
57+
assert 0 in self.g.map
58+
self.tx = from_binary(CTransaction, self.g.map[0])
59+
self.i = [from_binary(PSBTMap, f) for _ in self.tx.vin]
60+
self.o = [from_binary(PSBTMap, f) for _ in self.tx.vout]
61+
return self
62+
63+
def serialize(self):
64+
assert isinstance(self.g, PSBTMap)
65+
assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
66+
assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
67+
assert 0 in self.g.map
68+
tx = from_binary(CTransaction, self.g.map[0])
69+
assert len(tx.vin) == len(self.i)
70+
assert len(tx.vout) == len(self.o)
71+
72+
psbt = [x.serialize() for x in [self.g] + self.i + self.o]
73+
return b"psbt\xff" + b"".join(psbt)
74+
75+
def to_base64(self):
76+
return base64.b64encode(self.serialize()).decode("utf8")
77+
78+
@classmethod
79+
def from_base64(cls, b64psbt):
80+
return from_binary(cls, base64.b64decode(b64psbt))

0 commit comments

Comments
 (0)