neo-devpack-dotnet icon indicating copy to clipboard operation
neo-devpack-dotnet copied to clipboard

`BigInteger` comparer for `ByteString`

Open cschuchardt88 opened this issue 1 year ago • 17 comments

I don't know if this ApplicationEngine problem or compiler. But we need to do this. It compilers fine. But doesn't work. Because one is an Integer and one is a ByteString.

        public static bool Main(ByteString i)
        {
            ByteString stored = Storage.Get(Storage.CurrentContext, "i");
            return i == stored;
        }

cschuchardt88 avatar Jan 16 '24 07:01 cschuchardt88

@Jim8y

cschuchardt88 avatar Jan 16 '24 07:01 cschuchardt88

Wait, what? Aren't them all string?

Jim8y avatar Jan 16 '24 07:01 Jim8y

No, BigInteger is an Integer and the ByteString im guess is either a String or ByteArray

biginteger::main[1] ...
False
biginteger::main['\x01'] ...
True
biginteger::debugfunction main
VMState.BREAK SourceCodeBreakpoint BigIntegerTest.cs line 21 instructionPointer 47: return i == stored;
stored: {'type': 'ByteString', 'value': 'AQ=='}
i: {'type': 'Integer', 'value': '1'}

cschuchardt88 avatar Jan 16 '24 07:01 cschuchardt88

I mean in your code:

    public static bool Main(ByteString i)
        {
            ByteString stored = Storage.Get(Storage.CurrentContext, "i");
            return i == stored;
        }
ByteString i == ByteString stored

I dont see any problem here

Jim8y avatar Jan 16 '24 08:01 Jim8y

Passing an Integer in as a parameter will make it equal False. For example in the test if you pass in 1 it will be False and passing in \x01 will return True

cschuchardt88 avatar Jan 16 '24 08:01 cschuchardt88

I think the compiler is OK, because it is always just an INITSLOT for the start of a method.

Hecate2 avatar Jan 16 '24 08:01 Hecate2

How are you calling the method? In `RPC?

cschuchardt88 avatar Jan 16 '24 08:01 cschuchardt88

using System.ComponentModel;
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Attributes;
using Neo.SmartContract.Framework.Services;

namespace BigIntegerTest
{
    [DisplayName("BigIntegerTest")]
    [ManifestExtra("Author", "Hecate2")]
    [ManifestExtra("Email", "[email protected]")]
    [ManifestExtra("Description", "ByteString comparison")]
    public class BigIntegerTest : SmartContract
    {
        public static void _deploy(object data, bool update)
        {
            Storage.Put(Storage.CurrentContext, "i", 1);
        }
        public static bool Main(ByteString i)
        {
            ByteString stored = Storage.Get(Storage.CurrentContext, "i");
            return i == stored;
        }
    }
}
from neo_fairy_client import FairyClient, Hash160Str
user = Hash160Str('0xb1983fa2479a0c8e2beae032d2df564b5451b7a5')
c = FairyClient(fairy_session='biginteger', wallet_address_or_scripthash=user)
c.virutal_deploy_from_path('./bin/sc/BigIntegerTest.nef')
print(c.invokefunction('main', [1]))
print(c.invokefunction('main', ['\x01']))
c.delete_source_code_breakpoints()
c.set_source_code_breakpoint('BigIntegerTest.cs', 21)
print(c.debug_function_with_session('main', [1]))
print('stored:', c.get_variable_value_by_name('stored'))
print('i:', c.get_variable_value_by_name('i'))
biginteger::main[1] relay=True [{'account': '0xb1983fa2479a0c8e2beae032d2df564b5451b7a5', 'scopes': 'CalledByEntry', 'allowedcontracts': [], 'allowedgroups': [], 'rules': []}]
False
biginteger::main['\x01'] relay=True [{'account': '0xb1983fa2479a0c8e2beae032d2df564b5451b7a5', 'scopes': 'CalledByEntry', 'allowedcontracts': [], 'allowedgroups': [], 'rules': []}]
True
biginteger::debugfunction main[1]
VMState.BREAK SourceCodeBreakpoint BigIntegerTest.cs line 21 instructionPointer 47: return i == stored;
stored: {'type': 'ByteString', 'value': 'AQ=='}
i: {'type': 'Integer', 'value': '1'}

Hecate2 avatar Jan 16 '24 08:01 Hecate2

How are you calling the method? In `RPC?

Yes, in neo-fairy-client.

Hecate2 avatar Jan 16 '24 08:01 Hecate2

You using neon-js or RpcClient?

cschuchardt88 avatar Jan 16 '24 08:01 cschuchardt88

neo-fairy-client development by them is a very useful tool, @cschuchardt88 you can check it out.

Jim8y avatar Jan 16 '24 08:01 Jim8y

@Jim8y either way. There is a problem with the ByteString and BigInteger comparer in NCCS. Because ByteString == BigInteger is not equal when BigInteger. We need to add type checking validation or fix by CONVERT parameter to type that is specified in the parameter of the method. NCCS should fail it someone passes in a ByteArray into a parameter that is BigInteger unless you auto CONVERT to Biginteger. The types are to loose. You need to strict them to the types that they are. Because ApplicationEngine does care.

cschuchardt88 avatar Jan 16 '24 08:01 cschuchardt88

you want extra parameter type check,,,, make sense,,,, and we can make it, ABI actually contains the parameter type.

Jim8y avatar Jan 16 '24 08:01 Jim8y

@Jim8y looks like when you pass in type Integer into ApplicationEngine. It stores as Integer in VM. Which is ok. But compiler should have type checking and strict parameters to their type for the reason in our case. so NCCS should throw error for stored == i forcing you to do stored == (ByteString)i or stored == i.ToByteArray() in the contract. So this way NCCS generates an CONVERT opcode for in VM

cschuchardt88 avatar Jan 16 '24 08:01 cschuchardt88

In our contract example, we never defined any BigInteger, and it should be quite OK to compare two ByteStrings. Maybe we can add a method in the RPC and neo-cli to invoke contracts with strict types.

Hecate2 avatar Jan 16 '24 08:01 Hecate2

@Hecate2 we wouldn't have the contract manifest to compare too.

cschuchardt88 avatar Jan 16 '24 09:01 cschuchardt88

Hello, https://github.com/neo-project/neo/issues/1891.

roman-khimov avatar Jan 16 '24 11:01 roman-khimov