Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cast to boolean is not working #763

Closed
RawichK opened this issue Aug 18, 2022 · 6 comments
Closed

Cast to boolean is not working #763

RawichK opened this issue Aug 18, 2022 · 6 comments

Comments

@RawichK
Copy link

RawichK commented Aug 18, 2022

bool val = (bool)myProperties["isExist"];
bool test1 = val == true ? true : false;
bool test2 = val == false ? true : false;

Both test1 and test2 have false value.

When switching to the disassembly view, the value in LOC1 is the value 1.
So, the val == true is boiling down to 1 == true which fails.

@erikzhang
Copy link
Member

Can you provide the definition of myProperties?

@RawichK
Copy link
Author

RawichK commented Aug 25, 2022

it is a Map<string, object> type.

Map<string, object> myProperties = new();
myProperties["isExist"] = true;

@erikzhang
Copy link
Member

public static bool testCast()
{
    Map<string, object> myProperties = new();
    myProperties["isExist"] = true;
    bool val = (bool)myProperties["isExist"];
    bool test1 = val == true ? true : false;
    return test1;
}

It returns true.

@RawichK
Copy link
Author

RawichK commented Aug 26, 2022

I tried your snippet and it indeed returns true, my sample code cannot reflect the real case.
Because the actual data is loaded from storage and somehow it has been stored as 1 even the field is type bool from the beginning.
I have a workaround to use only bool test1 = val ? true : false;
If you would like to investigate further, I can share my private repo with you. Otherwise, I think we can close this issue. Because I cannot reproduce the storage written issue that writes true as 1 in toolkit version (3.3.0)

@igormcoelho
Copy link
Contributor

igormcoelho commented Aug 16, 2023

@RawichK Beware that casting can lead to erratic behavior, because C# Neo3 SDK may sometimes be invoked as an explicit operator, which is correct, or may be masked by some implicit C# conversion, which is incorrect, and seems to be the case for object directly to bool.
On general, avoid casting and explicitly declare the intended behavior. Below, I provide an IntegerToBoolean function, that works correctly, and can be optimized to bytecode if needed (to save some gas).
Note that testCase1 works correctly, but testCase2 is wrong... the reason is that (bool) casting does not actually convert the internal ByteString stack item into a Boolean stack item, leading to wrong interpretation in the smart contract. In this example, I cannot remove the (BigInteger) casting, but it is possible to improve the SDK to prevent such casting as well.

     public static event Action<string, bool> my_event_bool;
     
     public static bool IntegerToBool(BigInteger big) {
          return !(big == 0); 
      }

      public static bool testCast1() {
          Storage.Put(Storage.CurrentContext, "boolStored", 1);
          Map<string, object> myProperties = new();
          myProperties["isExist"] =  IntegerToBool((BigInteger)Storage.Get(Storage.CurrentContext, "boolStored"));
          bool val = (bool)myProperties["isExist"];
          // val is Boolean (true)
          my_event_bool("testCast1 val:", val);
          bool test1 = val == true ? true : false;
          // test1 is Boolean (true)
          my_event_bool("testCast1 final:", test1);
          return test1; // true (CORRECT)
      }

      public static bool testCast2()
      {
          Storage.Put(Storage.CurrentContext, "boolStored", 1);
          Map<string, object> myProperties = new();
          myProperties["isExist"] =  Storage.Get(Storage.CurrentContext, "boolStored");
          bool val = (bool)myProperties["isExist"];
          // val is ByteString (01)  
          my_event_bool("testCast2 val:", val);
          bool test1 = val == true ? true : false;
          // test1 is Boolean (false)
          my_event_bool("testCast2 final:", test1);
          return test1; // false (INCORRECT)
      }

@RawichK
Copy link
Author

RawichK commented Aug 19, 2023

Thank you @igormcoelho for the detail explanations.

@RawichK RawichK closed this as completed Aug 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants