Skip to content

Commit

Permalink
Move script functions from Output to Script
Browse files Browse the repository at this point in the history
  • Loading branch information
alecalve committed Sep 25, 2016
1 parent 4d3c855 commit f513fa0
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 62 deletions.
56 changes: 6 additions & 50 deletions blockchain_parser/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,11 @@
# modified, propagated, or distributed except according to the terms contained
# in the LICENSE file.

from bitcoin.core.script import *
from .utils import decode_varint, decode_uint64
from .script import Script
from .address import Address


def is_public_key(hex_data):
"""Given a bytes string, returns whether its is probably a bitcoin
public key or not. It doesn't actually ensures that the data is a valid
public key, justs that it looks like one
"""
if type(hex_data) != bytes:
return False

# Uncompressed public key
if len(hex_data) == 65 and hex_data[0] == 4:
return True

# Compressed public key
if len(hex_data) == 33 and hex_data[0] in [2, 3]:
return True

return False


class Output(object):
"""Represents a Transaction output"""

Expand Down Expand Up @@ -95,46 +75,22 @@ def addresses(self):
return self._addresses

def is_return(self):
return self.script.script.is_unspendable()
return self.script.is_return()

def is_p2sh(self):
return self.script.script.is_p2sh()
return self.script.is_p2sh()

def is_pubkey(self):
return len(self.script.operations) == 2 \
and self.script.operations[-1] == OP_CHECKSIG \
and is_public_key(self.script.operations[0])
return self.script.is_pubkey()

def is_pubkeyhash(self):
return len(self._script_hex) == 25 \
and self._script_hex[0] == OP_DUP \
and self._script_hex[1] == OP_HASH160 \
and self._script_hex[-2] == OP_EQUALVERIFY \
and self._script_hex[-1] == OP_CHECKSIG
return self.script.is_pubkeyhash()

def is_multisig(self):
if len(self.script.operations) < 4:
return False
m = self.script.operations[0]

if not type(m) == int:
return False

for i in range(m):
if not is_public_key(self.script.operations[1+i]):
return False

n = self.script.operations[-2]
if type(n) != int or n < m \
or self.script.operations[-1] != OP_CHECKMULTISIG:
return False

return True
return self.script.is_multisig()

def is_unknown(self):
return not self.is_pubkeyhash() and not self.is_pubkey() \
and not self.is_p2sh() and not self.is_multisig() \
and not self.is_return()
return self.script.is_unknown()

@property
def type(self):
Expand Down
63 changes: 62 additions & 1 deletion blockchain_parser/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,29 @@
# modified, propagated, or distributed except according to the terms contained
# in the LICENSE file.

from bitcoin.core.script import CScript, CScriptInvalidError
from bitcoin.core.script import *
from binascii import b2a_hex


def is_public_key(hex_data):
"""Given a bytes string, returns whether its is probably a bitcoin
public key or not. It doesn't actually ensures that the data is a valid
public key, justs that it looks like one
"""
if type(hex_data) != bytes:
return False

# Uncompressed public key
if len(hex_data) == 65 and hex_data[0] == 4:
return True

# Compressed public key
if len(hex_data) == 33 and hex_data[0] in [2, 3]:
return True

return False


class Script(object):
"""Represents a bitcoin script contained in an input or output"""

Expand Down Expand Up @@ -71,3 +90,45 @@ def value(self):
self._value = " ".join(representations)

return self._value

def is_return(self):
return self.script.is_unspendable()

def is_p2sh(self):
return self.script.is_p2sh()

def is_pubkey(self):
return len(self.operations) == 2 \
and self.operations[-1] == OP_CHECKSIG \
and is_public_key(self.operations[0])

def is_pubkeyhash(self):
return len(self.hex) == 25 \
and self.hex[0] == OP_DUP \
and self.hex[1] == OP_HASH160 \
and self.hex[-2] == OP_EQUALVERIFY \
and self.hex[-1] == OP_CHECKSIG

def is_multisig(self):
if len(self.operations) < 4:
return False
m = self.operations[0]

if not isinstance(m, int):
return False

for i in range(m):
if not is_public_key(self.operations[1+i]):
return False

n = self.operations[-2]
if not isinstance(n, int) or n < m \
or self.operations[-1] != OP_CHECKMULTISIG:
return False

return True

def is_unknown(self):
return not self.is_pubkeyhash() and not self.is_pubkey() \
and not self.is_p2sh() and not self.is_multisig() \
and not self.is_return()
11 changes: 1 addition & 10 deletions blockchain_parser/tests/test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import unittest
from binascii import a2b_hex

from blockchain_parser.output import Output, is_public_key
from blockchain_parser.output import Output


class TestOutput(unittest.TestCase):
Expand Down Expand Up @@ -64,12 +64,3 @@ def test_unknown_from_hex(self):
output = Output.from_hex(a2b_hex(raw_output))
self.assertEqual("unknown", output.type)
self.assertEqual(0, len(output.addresses))

def test_is_public_key(self):
case1 = "010000000000000017a91471c5c3727fac8dbace94bd38cf8ac16a034a7" \
"94787"
self.assertFalse(is_public_key(a2b_hex(case1)))
self.assertFalse(is_public_key(None))
case3 = "02c0993f639534d348e1dca30566491e6cb11c14afa13ec244c05396a98" \
"39aeb17"
self.assertTrue(is_public_key(a2b_hex(case3)))
11 changes: 10 additions & 1 deletion blockchain_parser/tests/test_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import unittest
from binascii import a2b_hex
from blockchain_parser.script import Script
from blockchain_parser.script import Script, is_public_key


class TestScript(unittest.TestCase):
Expand All @@ -24,3 +24,12 @@ def test_invalid_script(self):
case = "40"
script = Script.from_hex(a2b_hex(case))
self.assertEqual("INVALID_SCRIPT", script.value)

def test_is_public_key(self):
case1 = "010000000000000017a91471c5c3727fac8dbace94bd38cf8ac16a034a7" \
"94787"
self.assertFalse(is_public_key(a2b_hex(case1)))
self.assertFalse(is_public_key(None))
case3 = "02c0993f639534d348e1dca30566491e6cb11c14afa13ec244c05396a98" \
"39aeb17"
self.assertTrue(is_public_key(a2b_hex(case3)))

0 comments on commit f513fa0

Please sign in to comment.