vbuterin / pybitcointools

SImple, common-sense Bitcoin-themed Python ECC library
1.28k stars 856 forks source link

op_return #142

Open dadaista opened 8 years ago

dadaista commented 8 years ago

Hi, great project. is there actually a way to build a tx with op_return and 40bytes message?

wizardofozzie commented 8 years ago

See my fork:

# mk_opreturn("the 80 byte message to be encoded", "01000000013543534354...00000000")
def mk_opreturn(msg, txhex=None):
    """Makes OP_RETURN script from msg, embeds in Tx hex"""    
    hexdata = safe_hexlify(b'\x6a' + wrap_script(msg))
    if txhex is None:
        return hexdata
    else:
        if not re.match("^[0-9a-fA-F]*$", txhex):
            return unhexlify(mk_opreturn(msg, hexlify(txhex)))
        elif isinstance(txhex, dict):
            txo = txhex
            outs = txo.get('outs')
        else:
            outs = deserialize(txhex).get('outs')

        txo = deserialize(txhex)
        assert (len(outs) > 0) and sum(multiaccess(outs, 'value')) > 0 \
                and not any([o for o in outs if o.get("script")[:2] == '6a']), "Tx limited to *1* OP_RETURN, and only whilst the other outputs send funds"
        outs.append({
                    'script': hexdata, 
                    'value': 0
                    })
        return serialize(txo)

## code from main.py

def num_to_var_int(x):
    x = int(x)
    if x < 253:       return from_int_to_byte(x)
    elif x < 2**16:   return from_int_to_byte(253) + encode(x, 256, 2)[::-1]
    elif x < 2**32:   return from_int_to_byte(254) + encode(x, 256, 4)[::-1]
    elif x < 2**64:   return from_int_to_byte(255) + encode(x, 256, 8)[::-1]
    else:             raise ValueError(x < 2**64)

def num_to_op_push(x):
    x = int(x)
    if 0 <= x <= 75:              
        pc = ''
        num = encode(x, 256, 1)
    elif x < 0xff:          
        pc = from_int_to_byte(0x4c)
        num = encode(x, 256, 1)
    elif x < 0xffff:        
        pc = from_int_to_byte(0x4d)
        num = encode(x, 256, 2)[::-1]
    elif x < 0xffffffff:
        pc = from_int_to_byte(0x4e)
        num = encode(x, 256, 4)[::-1]
    else: 
        raise ValueError("0xffffffff > value >= 0")
    return pc + num

def wrap_varint(hexdata):
    if re.match('^[0-9a-fA-F]*$', hexdata):
        return safe_hexlify(wrap_varint(safe_unhexlify(hexdata)))
    return num_to_var_int(len(hexdata)) + hexdata

def wrap_script(hexdata):
    if re.match('^[0-9a-fA-F]*$', hexdata):
        return safe_hexlify(wrap_script(safe_unhexlify(hexdata)))
    return num_to_op_push(len(hexdata)) + hexdata
dadaista commented 8 years ago

Thanks. It turns out that using the library either I made a mistake or some strange happened. I built the a new priv/pub/addr and refilled addr from another wallet, and then tryed to build a tx from addr to another of my wallets. It happened that the coin has been hijacked to an unknown (for me) address 13wCwgttgJFYZVJmvWb6kGbg1FJNf9U9EY

which by the way, cannot be generated by mistake because is a real address with an history of transactions back to the previous week.

Any hints, have you idea from which this 13wCwgttgJFYZVJmvWb6kGbg1FJNf9U9EY is coming from?

slush0 commented 8 years ago

You probably used some weak brainwallet and your coins has been stolen. Pretty common nowadays :).