p2wpkhはBIP0173で定義されているBech32というアドレス形式を使用する
p2shでp2wpkhをラップする… Segwitスクリプトがp2shのRedeemScriptでネストされる
BIP0141以前
01000000 – version
01 – # of inputs
712e…2f – previous tx hash
00000000 – previous tx index
1715…96 – ScriptSig
feffffff – sequence
02 – # of outputs
3236…00 output amount
1976…ac ScriptPubKey
075a0700 – locktime
BIP0141以降
01000000 – version
00 – Segwit marker
01 – Segwit flag
01 – # of inputs
712e…2f – previous tx hash
00000000 – previous tx index
1716…96 – ScriptSig
feffffff – sequence
02 – # of outputs
3236…00 output amount
1976…ac ScriptPubKey
0248…61 – witness
075a0700 – locktime
p2wpkhとの違いは、ScriptSigが空ではないこと, RedeemScriptがある
@classmethod
def parse(cls, s, testnet=False):
s.read(4)
if s.read(1) == b'\x00':
parse_method = cls.parse_segwit
else:
parse_method = cls.parse_legacy
s.seek(-5, 1)
return parse_method(s, testnet=testnet)
@classmethod
def parse_legacy(cls, s, testnet=False):
version = little_endian_to_int(s.read(4))
num_inputs = read_varint(s)
inputs = []
for _ in range(num_inputs):
inputs.append(TxIn.parse(s))
num_outputs = read_varint(s)
outputs = []
for _ in range(num_outputs):
outputs.append(TxOut.parse(s))
locktime = little_endian_to_int(s.read(4))
return cls(version, inputs, outputs, locktime, testnet=testnet, segwit=False)
@classmethod
def parse_segwit(cls, s, testnet=False):
version = little_endian_to_int(s.read(4))
marker = s.read(2)
if marker != b'\x00\x01':
raise RuntimeError('Not a segwit transaction {}'.format(marker))
num_inputs = read_varint(s)
inputs = []
for _ in range(num_inputs):
inputs.append(TxIn.parse(s))
num_outputs = read_varint(s)
outputs = []
for _ in range(num_outputs):
outputs.append(TxOut.parse(s))
for tx_in in inputs:
num_items = read_varint(s)
items = []
for _ in range(num_items):
item_len = read_varint(s)
if item_len == 0:
items.append(0)
else:
items.append(s.read(item_len))
tx_in.witness = items
locktime = little_endian_to_int(s.read(4))
return cls(version, inputs, outputs, locktime, testnet=testnet, segwit=True)
def serialize(self):
if self.segwit:
return self.serialize_segwit()
else:
return self.serialize_legacy()
def serialize_legacy(self):
result = int_to_little_endian(self.version, 4)
result += encode_varint(len(self.tx_ins))
for tx_in in self.tx_ins:
result += tx_in.serialize()
result += encode_varint(len(self.tx_outs))
for tx_out in self.tx_outs:
result += tx_out.serialize()
result += int_to_little_endian(self.locktime, 4)
return result
def serialize_segwit(self):
result = int_to_little_endian(self.version, 4)
result += b'\x00\x01'
result += encode_varint(len(self.tx_ins))
for tx_in in self.tx_ins:
result += tx_in.serialize()
result += encode_varint(len(self.tx_outs))
for tx_out in self.tx_outs:
result += tx_out.serialize()
for tx_in in self.tx_ins:
result += int_to_little_endian(len(tx_in.witness), 1)
for item in tx_in.witness:
if type(item) == int:
result += int_to_little_endian(item, 1)
else:
result += encode_varint(len(item)) + item
result += int_to_little_endian(self.locktime, 4)
return result
//
def sig_hash_bip143(self, input_index, redeem_script=None, witness_script=None):
tx_in = self.tx_ins[input_index]
s = int_to_little_endian(self.version, 4)
s += self.hash_prevouts() + self.hash_sequence()
s += tx_in.prev_tx[::-1] + int_to_little_endian(tx_in.prev_index, 4)
if witness_script:
script_code = witness_script.serialize()
elif redeem_script:
script_code = p2pkh_script(redeem_script.cmds[1]).serialize()
else:
script_code = p2pkh_script(tx_in.script_pubkey(self.testnet).cmds[1]).serialize()
s += script_code
s += int_to_little_endian(tx_in.value(), 8)
s += int_to_little_endian(tx_in.sequence, 4)
s += self.hash_outputs()
s += int_to_little_endian(self.locktime, 4)
s += int_to_little_endian(SIGHASH_ALL, 4)
return int.from_bytes(hash256(s), 'big')