各コマンドがオプコードかスタックにプッシュされるオプコードかを判定する
1~77まではエレメントでそれ以上(78以上)がオプコードとみなす
class Script: def __init__(self, cmds=None): if cmds is None: self.cmds = [] else: self.cmds = cmds // omission @classmethod def parse(cls, s): length = read_varint(s) cmds = [] count = 0 while count < length: current = s.read(1) count += 1 current_byte = current[0] if current_byte >= 1 and current_byte <= 75: n = current_byte cmds.append(s.read(n)) count += n elif current_byte == 76: data_length = little_endian_to_int(s.read(1)) count += data_length + 1 elif current_byte == 77: data_length = little_endian_to_int(s.read(2)) cmds.append(s.read(data_length)) count += data_length + 2 else: op_code = current_byte cmds.append(op_code) if count != length: raise SyntaxError('parsing script failed') return cls(cmds)
### シリアライズ
整数の場合はオプコード、それ以外はエレメント
class Script: // def raw_serialize(self): result = b'' for cmd in self.cmds: if type(cmd) == int: result += into_to_little_endian(cmd, 1) else: length = len(cmd) if length < 75: result += int_to_little_endian(length, 1) elif length > 75 and length < 0x100: result += int_to_little_endian(76, 1) result += int_to_little_endian(length, 1) elif length >= 0x100 and length <= 520: result += int_to_little_endian(77, 1) result += int_to_little_endian(length, 2) else: raise ValueError('too long an cmd') result += cmd return result def serialize(self): result = self.raw_serialize() total = len(result) return encode_varint(total) + result
### Script Fieldの連結
scriptオブジェクトは評価が必要なコマンドのセットを表す
スクリプを評価するにあたり、ロックボックスのScriptPubKey(outputsの2番目)とアンロックするScriptSig(inputsの3番目)のフィールドを連結する必要がある。
ScriptPubKeyはPrevious Transaction, ScriptSigはCurrent Transaction
ScriptSigがScriptPubKeyをunlockする
ScriptSigからのコマンドはScriptPubKeyのコマンドの上に配置し、処理するコマンドがなくなるまで1つづつ処理される
class Script: def __add__(self, other): return Script(self.cmds + other.cmds)
標準スクリプト(Base58, Bech32)
p2pk, p2pkh, p2sh, p2wpkh, p2wsh
ウォレットは様々なタイプを解釈する方法を知っており、適切なScriptPubKeyを作成する