def op_for_int(self, value): """Get a small int or push operation for value.""" cls = types.opcode_by_name('OP_%d' % value) if cls: return cls() value = formats.int_to_bytearray(value) return types.Push(data=value)
def op_for_int(self, value): """Get a small int or push operation for value.""" cls = types.opcode_by_name('OP_%d'%value) if cls: return cls() value = formats.int_to_bytearray(value) return types.Push(data=value)
def format_structural_op(op): """Format an op for human-readability.""" def format_statements(statements): return '; '.join(map(format_structural_op, statements)) + ';' def format_args(arguments): args = map(format_structural_op, arguments) args_str = '' for i, arg in enumerate(args): args_str += arg if i < len(args) - 1: args_str += ', ' return args_str if isinstance(op, structural_nodes.Script): return format_statements(op.statements) elif isinstance(op, (structural_nodes.Int, structural_nodes.Bytes, structural_nodes.Symbol)): s = str(op) # Hex-encode numeric values. if isinstance(op, (structural_nodes.Int, structural_nodes.Bytes)) and abs(int(op)) > 16: s = hex(int(op)) return s elif isinstance(op, structural_nodes.Declaration): return 'let %s%s = %s' % ('mutable ' if op.mutable else '', op.name, format_structural_op(op.value)) elif isinstance(op, structural_nodes.Assignment): return '%s = %s' % (op.name, format_structural_op(op.value)) elif isinstance(op, structural_nodes.Function): args_str = format_args(op.args) body_str = format_statements(op.body) return 'func %s(%s) {%s}' % (op.name, args_str, body_str) elif isinstance(op, structural_nodes.FunctionCall): args_str = format_args(op.args) return '%s(%s)' % (op.name, args_str) elif isinstance(op, structural_nodes.If): test = format_structural_op(op.test) true_branch = format_statements(op.truebranch) s = 'if %s {%s}' % (test, true_branch) if op.falsebranch: s += ' else {%s}' % format_statements(op.falsebranch) return s elif isinstance(op, structural_nodes.InnerScript): return format_statements(op.statements) if not hasattr(op, 'name'): return linear = linear_nodes.opcode_by_name(op.name) if not linear: return if not linear.opstr: return op.name if linear.is_unary(): return linear.opstr.format(format_structural_op(op.operand)) elif linear.is_binary(): return linear.opstr.format(*map(format_structural_op, [op.left, op.right])) elif linear.is_ternary(): return linear.opstr.format(*map(format_structural_op, op.operands[0:3]))
def process_value(self, value): # Encode integer. if isinstance(value, (int, long)): push = formats.int_to_bytearray(value) self.add_instruction(types.Push(data=push)) else: try: opcode = types.small_int_opcode(int(value))() except (TypeError, ValueError): opcode = types.opcode_by_name('OP_%s' % value)() self.add_instruction(opcode)
def process_value(self, value): # Encode integer. if isinstance(value, int): push = formats.int_to_bytearray(value) self.add_instruction(types.Push(data=push)) else: try: opcode = types.small_int_opcode(int(value))() except (TypeError, ValueError): opcode = types.opcode_by_name('OP_%s' % value)() self.add_instruction(opcode)
def visit_UnaryOpCode(self, node): if SInstructions.is_arithmetic_op(node) and isinstance(node.operand, (structural_nodes.Int, structural_nodes.Bytes)): if not formats.is_strict_num(int(node.operand)): msg = 'Input value to %s is longer than 4 bytes: 0x%x' % (node.name, node.operand) if self.options.strict_num: self.error(msg, node.lineno) raise IRStrictNumError(msg) else: self.warning(msg, node.lineno) return_value = self.visit(node.operand) op = types.opcode_by_name(node.name)() return return_value + [op]
def merge_op_and_verify(instructions): """Merge opcodes with a corresponding *VERIFY form. e.g. OP_EQUAL OP_VERIFY -> OP_EQUALVERIFY """ optimizations = [] for op in types.iter_opcode_classes(): if op.name.endswith('VERIFY') and op.name != 'OP_VERIFY': base_op = types.opcode_by_name(op.name[:-6]) if not base_op: continue template = [base_op(), types.Verify()] optimizations.append((template, [op()])) for template, replacement in optimizations: callback = lambda values, replacement=replacement: replacement instructions.replace_template(template, callback)
def visit_BinOpCode(self, node): # Check for values longer than 4 bytes. if SInstructions.is_arithmetic_op(node): operands = [node.left, node.right] if all(isinstance(i, (structural_nodes.Int, structural_nodes.Bytes)) for i in operands): valid = [formats.is_strict_num(int(i)) for i in operands] if False in valid: msg = 'Input value to %s is longer than 4 bytes: 0x%x' % (node.name, operands[valid.index(False)]) if self.options.strict_num: self.error(msg, node.lineno) raise IRStrictNumError(msg) else: self.warning(msg, node.lineno) return_value = self.visit(node.left) return_value.extend(self.visit(node.right)) op = types.opcode_by_name(node.name)() return return_value + [op]
def transform(self, source): if isinstance(source, list): source = ''.join(source) if source.startswith('0x'): source = source[2:] src = script.CScript(x(source)) iterator = iter(src) for value in iterator: op = None s = str(value) if s.startswith('OP_'): op = types.opcode_by_name(s)() elif isinstance(value, int): op = types.small_int_opcode(value)() else: op = types.Push(data=value) if op is not None: self.add_instruction(op) return self.instructions
def visit_BinOpCode(self, node): return_value = self.visit(node.left) return_value.extend(self.visit(node.right)) op = types.opcode_by_name(node.name)() return return_value + [op]
def is_byte_string_op(op): """Return whether op operates on a string of bytes.""" linear = linear_nodes.opcode_by_name(op.name) if not linear or not issubclass(linear, linear_nodes.OpCode): return False return linear.byte_manipulator
def is_arithmetic_op(op): """Return whether op represents an arithmetic operation.""" linear = linear_nodes.opcode_by_name(op.name) if not linear or not issubclass(linear, linear_nodes.OpCode): return False return linear.arithmetic
def visit_OpCode(self, node): op = types.opcode_by_name(node.name)() return op
def visit_VariableArgsOpCode(self, node): return_value = [] for arg in node.operands: return_value.extend(self.visit(arg)) op = types.opcode_by_name(node.name)() return return_value + [op]
def visit_UnaryOpCode(self, node): return_value = self.visit(node.operand) op = types.opcode_by_name(node.name)() return return_value + [op]
def visit_VerifyOpCode(self, node): return_value = self.visit(node.test) op = types.opcode_by_name(node.name)() return return_value + [op]