mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-07 17:00:32 +02:00
refactor: move PSBT(Map) helpers from signet miner to test framework
Can be easily reviewed with `--color-moved=dimmed-zebra`.
This commit is contained in:
@ -4,7 +4,6 @@
|
|||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import base64
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
@ -20,7 +19,8 @@ PATH_BASE_TEST_FUNCTIONAL = os.path.abspath(os.path.join(PATH_BASE_CONTRIB_SIGNE
|
|||||||
sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL)
|
sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL)
|
||||||
|
|
||||||
from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height # noqa: E402
|
from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height # noqa: E402
|
||||||
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
|
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
|
||||||
|
from test_framework.psbt import PSBT, PSBTMap # noqa: E402
|
||||||
from test_framework.script import CScriptOp # noqa: E402
|
from test_framework.script import CScriptOp # noqa: E402
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@ -32,76 +32,6 @@ SIGNET_HEADER = b"\xec\xc7\xda\xa2"
|
|||||||
PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed
|
PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed
|
||||||
RE_MULTIMINER = re.compile("^(\d+)(-(\d+))?/(\d+)$")
|
RE_MULTIMINER = re.compile("^(\d+)(-(\d+))?/(\d+)$")
|
||||||
|
|
||||||
# #### some helpers that could go into test_framework
|
|
||||||
|
|
||||||
class PSBTMap:
|
|
||||||
"""Class for serializing and deserializing PSBT maps"""
|
|
||||||
|
|
||||||
def __init__(self, map=None):
|
|
||||||
self.map = map if map is not None else {}
|
|
||||||
|
|
||||||
def deserialize(self, f):
|
|
||||||
m = {}
|
|
||||||
while True:
|
|
||||||
k = deser_string(f)
|
|
||||||
if len(k) == 0:
|
|
||||||
break
|
|
||||||
v = deser_string(f)
|
|
||||||
if len(k) == 1:
|
|
||||||
k = k[0]
|
|
||||||
assert k not in m
|
|
||||||
m[k] = v
|
|
||||||
self.map = m
|
|
||||||
|
|
||||||
def serialize(self):
|
|
||||||
m = b""
|
|
||||||
for k,v in self.map.items():
|
|
||||||
if isinstance(k, int) and 0 <= k and k <= 255:
|
|
||||||
k = bytes([k])
|
|
||||||
m += ser_compact_size(len(k)) + k
|
|
||||||
m += ser_compact_size(len(v)) + v
|
|
||||||
m += b"\x00"
|
|
||||||
return m
|
|
||||||
|
|
||||||
class PSBT:
|
|
||||||
"""Class for serializing and deserializing PSBTs"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.g = PSBTMap()
|
|
||||||
self.i = []
|
|
||||||
self.o = []
|
|
||||||
self.tx = None
|
|
||||||
|
|
||||||
def deserialize(self, f):
|
|
||||||
assert f.read(5) == b"psbt\xff"
|
|
||||||
self.g = from_binary(PSBTMap, f)
|
|
||||||
assert 0 in self.g.map
|
|
||||||
self.tx = from_binary(CTransaction, self.g.map[0])
|
|
||||||
self.i = [from_binary(PSBTMap, f) for _ in self.tx.vin]
|
|
||||||
self.o = [from_binary(PSBTMap, f) for _ in self.tx.vout]
|
|
||||||
return self
|
|
||||||
|
|
||||||
def serialize(self):
|
|
||||||
assert isinstance(self.g, PSBTMap)
|
|
||||||
assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
|
|
||||||
assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
|
|
||||||
assert 0 in self.g.map
|
|
||||||
tx = from_binary(CTransaction, self.g.map[0])
|
|
||||||
assert len(tx.vin) == len(self.i)
|
|
||||||
assert len(tx.vout) == len(self.o)
|
|
||||||
|
|
||||||
psbt = [x.serialize() for x in [self.g] + self.i + self.o]
|
|
||||||
return b"psbt\xff" + b"".join(psbt)
|
|
||||||
|
|
||||||
def to_base64(self):
|
|
||||||
return base64.b64encode(self.serialize()).decode("utf8")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_base64(cls, b64psbt):
|
|
||||||
return from_binary(cls, base64.b64decode(b64psbt))
|
|
||||||
|
|
||||||
# #####
|
|
||||||
|
|
||||||
def create_coinbase(height, value, spk):
|
def create_coinbase(height, value, spk):
|
||||||
cb = CTransaction()
|
cb = CTransaction()
|
||||||
cb.vin = [CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff)]
|
cb.vin = [CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff)]
|
||||||
|
80
test/functional/test_framework/psbt.py
Normal file
80
test/functional/test_framework/psbt.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2022 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
import base64
|
||||||
|
|
||||||
|
from .messages import (
|
||||||
|
CTransaction,
|
||||||
|
deser_string,
|
||||||
|
from_binary,
|
||||||
|
ser_compact_size,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PSBTMap:
|
||||||
|
"""Class for serializing and deserializing PSBT maps"""
|
||||||
|
|
||||||
|
def __init__(self, map=None):
|
||||||
|
self.map = map if map is not None else {}
|
||||||
|
|
||||||
|
def deserialize(self, f):
|
||||||
|
m = {}
|
||||||
|
while True:
|
||||||
|
k = deser_string(f)
|
||||||
|
if len(k) == 0:
|
||||||
|
break
|
||||||
|
v = deser_string(f)
|
||||||
|
if len(k) == 1:
|
||||||
|
k = k[0]
|
||||||
|
assert k not in m
|
||||||
|
m[k] = v
|
||||||
|
self.map = m
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
m = b""
|
||||||
|
for k,v in self.map.items():
|
||||||
|
if isinstance(k, int) and 0 <= k and k <= 255:
|
||||||
|
k = bytes([k])
|
||||||
|
m += ser_compact_size(len(k)) + k
|
||||||
|
m += ser_compact_size(len(v)) + v
|
||||||
|
m += b"\x00"
|
||||||
|
return m
|
||||||
|
|
||||||
|
class PSBT:
|
||||||
|
"""Class for serializing and deserializing PSBTs"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.g = PSBTMap()
|
||||||
|
self.i = []
|
||||||
|
self.o = []
|
||||||
|
self.tx = None
|
||||||
|
|
||||||
|
def deserialize(self, f):
|
||||||
|
assert f.read(5) == b"psbt\xff"
|
||||||
|
self.g = from_binary(PSBTMap, f)
|
||||||
|
assert 0 in self.g.map
|
||||||
|
self.tx = from_binary(CTransaction, self.g.map[0])
|
||||||
|
self.i = [from_binary(PSBTMap, f) for _ in self.tx.vin]
|
||||||
|
self.o = [from_binary(PSBTMap, f) for _ in self.tx.vout]
|
||||||
|
return self
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
assert isinstance(self.g, PSBTMap)
|
||||||
|
assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
|
||||||
|
assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
|
||||||
|
assert 0 in self.g.map
|
||||||
|
tx = from_binary(CTransaction, self.g.map[0])
|
||||||
|
assert len(tx.vin) == len(self.i)
|
||||||
|
assert len(tx.vout) == len(self.o)
|
||||||
|
|
||||||
|
psbt = [x.serialize() for x in [self.g] + self.i + self.o]
|
||||||
|
return b"psbt\xff" + b"".join(psbt)
|
||||||
|
|
||||||
|
def to_base64(self):
|
||||||
|
return base64.b64encode(self.serialize()).decode("utf8")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_base64(cls, b64psbt):
|
||||||
|
return from_binary(cls, base64.b64decode(b64psbt))
|
Reference in New Issue
Block a user