CityOfZion / neo-boa

Python compiler for the Neo2 Virtual Machine, see neo3-boa for NEO3
MIT License
69 stars 55 forks source link

Smart Contract Migration results in different return value #115

Closed corck closed 5 years ago

corck commented 5 years ago

I'm currently trying to implement smart contract migration into my token, but it fails. Have now created a sample repo to investigate a bit more.

To make it less error prone on my side, I've copied the values from the tests in this repo and used the simple examples from the neo-python docs, slightly modified. I store simply a number and then get that again.

When I normally deploy the contract all looks good, like the one I use in the beginning.

 > sc invoke 0x0546b7c512bd2fc13d5579b35e5ed84602e576ac balance ['BBB']
 ---------------------------
Test invoke successful
Total operations: 61
Results [{'type': 'ByteArray', 'value': '01'}]
Invoke TX GAS cost: 0.0
Invoke TX fee: 0.0001
----------------------------

neo> [I 190412 11:45:08 EventHub:62] [SmartContract.Execution.Success][7492] [060b418755cdd2bb594a8a58d6c4947e960a1cdb] [tx 52c53d0ad1c2054164a8e0ac85ac8c136bb16dc5d44d72dd104c872c94372001] {'type': 'Array', 'value': [{'type': 'Array', 'value': [{'type': 'ByteArray', 'value': b'2y\x06'}]}, {'type': 'ByteArray', 'value': b'balance'}]}

However when I invoke the migrated contract it the result is an Array

# The migrated coontract however returns

> sc invoke 0x060b418755cdd2bb594a8a58d6c4947e960a1cdb balance ['BBB']

--------------------------
Test invoke successful
Total operations: 7
Results [{'type': 'Array', 'value': [{'type': 'ByteArray', 'value': '327906'}]}, {'type': 'ByteArray', 'value': '62616c616e6365'}]
Invoke TX GAS cost: 0.0
Invoke TX fee: 0.0001
--------------------------

The migration looks like this

    elif operation == 'migrate':    
        print("Migrate operation") 

        # taken out of neo boa test example
        param_list = bytearray(b'\x07\x10')
        return_type = bytearray(b'\x05')
        properties = 1
        name = 'migrated contract 3'
        version = '0.3'
        author = 'localhuman3'
        email = 'nex@email.com'
        description = 'test migrate3'

        new_contract = Migrate(args[0], param_list, return_type, properties, name, version, author, email, description)
        print("contract migrated")

        return new_contract

which I invoke like this

sc invoke 0xe1d955a7a6c2c2af58eb2ea0abf28f3a2a9ee568 migrate [0x011fc56b6a00527ac46a51527ac468164e656f2e53746f726167652e476574436f6e74657874616a52527ac46a00c30361646487646e0006616464696e67680f4e656f2e52756e74696d652e4c6f676a52c36a51c300c37c680f4e656f2e53746f726167652e476574616a53527ac46a53c36a51c351c3936a54527ac46a52c36a51c300c36a54c35272680f4e656f2e53746f726167652e507574616a54c36c7566616a00c30672656d6f7665876454006a52c36a51c300c37c680f4e656f2e53746f726167652e476574616a53527ac46a52c36a51c300c36a53c36a51c351c3945272680f4e656f2e53746f726167652e507574616a53c36a51c351c3946c7566616a00c30762616c616e6365876421006a52c36a51c300c37c680f4e656f2e53746f726167652e476574616c7566616a00c3076d69677261746587642401174d696772617465206f7065726174696f6e207374617274680f4e656f2e52756e74696d652e4c6f670207106a55527ac401056a56527ac4516a57527ac4136d6967726174656420636f6e747261637420336a58527ac403302e336a59527ac40b6c6f63616c68756d616e336a5a527ac40d6e657840656d61696c2e636f6d6a5b527ac40d74657374206d696772617465336a5c527ac46a51c300c36a55c36a56c36a57c36a58c36a59c36a5ac36a5bc36a5cc3587951795a727551727557795279597275527275567953795872755372755579547957727554727568144e656f2e436f6e74726163742e4d696772617465616a5d527ac411636f6e7472616374206d69677261746564680f4e656f2e52756e74696d652e4c6f676a5dc36c756661006c7566] 

I'm using the neo-python version 0.8.4 from current neo-local repo.

I've created a repository with instructions in the README to follow along my steps and to be able to replicate.

corck commented 5 years ago

@hal0x2328 pointed out in Discord that I was passing the script in the wrong format.

If you put 0x in front of your argument, np-prompt assumes you are specifying a really large little-endian BigInteger. So your contract script ends up on the blockchain but the bytes are in reverse order. If you want to send a bytearray do it like shown here

so what needs to be done is to convert the script hex to a bytearray

#!/usr/local/env python3

import binascii

script="011fc56b6a00527ac46a51527ac468164e656f2e53746f726167652e476574436f6e74657874616a52527ac46a00c30361646487646e0006616464696e67680f4e656f2e52756e74696d652e4c6f676a52c36a51c300c37c680f4e656f2e53746f726167652e476574616a53527ac46a53c36a51c351c3936a54527ac46a52c36a51c300c36a54c35272680f4e656f2e53746f726167652e507574616a54c36c7566616a00c30672656d6f7665876454006a52c36a51c300c37c680f4e656f2e53746f726167652e476574616a53527ac46a52c36a51c300c36a53c36a51c351c3945272680f4e656f2e53746f726167652e507574616a53c36a51c351c3946c7566616a00c30762616c616e6365876421006a52c36a51c300c37c680f4e656f2e53746f726167652e476574616c7566616a00c3076d69677261746587642401174d696772617465206f7065726174696f6e207374617274680f4e656f2e52756e74696d652e4c6f670207106a55527ac401056a56527ac4516a57527ac4136d6967726174656420636f6e747261637420336a58527ac403302e336a59527ac40b6c6f63616c68756d616e336a5a527ac40d6e657840656d61696c2e636f6d6a5b527ac40d74657374206d696772617465336a5c527ac46a51c300c36a55c36a56c36a57c36a58c36a59c36a5ac36a5bc36a5cc3587951795a727551727557795279597275527275567953795872755372755579547957727554727568144e656f2e436f6e74726163742e4d696772617465616a5d527ac411636f6e7472616374206d69677261746564680f4e656f2e52756e74696d652e4c6f676a5dc36c756661006c7566"

print("'{}'".format(''.join(['\\x{:02x}'.format(ord(c)) for c in binascii.unhexlify(script).decode('Latin1')])))