Skip to content
This repository has been archived by the owner on Feb 17, 2023. It is now read-only.

Comparison of two Ints leads to transaction error 9 — “Cell underflow” #3

Closed
anstill opened this issue Jan 27, 2023 · 11 comments
Closed

Comments

@anstill
Copy link

anstill commented Jan 27, 2023

Code in Tact:

let a: Int = 1;

let b:int = 2;

let c:int = -1;

if(a == b) {
// do smth
}

Generated code in Func:

int $a = 1;
int $b = 2;
int $c = (-1); 

 if (($a == $b)) {
    }

This leads to a transaction error 9 — “Cell underflow”.

I suppose generated code should look like this:

int $a = 1;
int $b = 2;
int $c = -1

 if ($a == $b) {
    }
@ex3ndr
Copy link
Contributor

ex3ndr commented Jan 27, 2023

No, this couldn't be a reason. Error is thrown somewhere else.

@anstill
Copy link
Author

anstill commented Jan 27, 2023

@ex3ndr You are right, I found the reason. I'm using native udict_get_next to iterate on map keys.

struct DataRaw {
    key: Int;
    cs: Slice;
    f: Int;
}

struct Data {
    validUntil: Int as uint64;
    payload: Slice;
}

@name(udict_get_next?)
native mapGetNext(map: map[Int]Data, keyLen: Int, pivot: Int): DataRaw;

contract HasMapContract with Deployable, Ownable {  
  data: map[Int]Data;
  
  receive(msg: Delete) {
    // ...code
    
    let nextKey: DataRaw = mapGetNext(self.data, 256, -1);
    
    if(nextKey.key == 1) {
      // this if triggers error;
    } 
    
  }

Do you know what is wrong here? I am also looking for a proper way to iterate on the map keys without knowing them.

@ex3ndr
Copy link
Contributor

ex3ndr commented Jan 27, 2023

I am thinking about a solution, but it is not possible for now.

But your dict ops are for unsigned keys, but singed one is defined.

@anstill
Copy link
Author

anstill commented Jan 28, 2023

@ex3ndr I tried to change different types of variables, but still getting errors when interacting with any variable from udict_get_next.

The declaration looks like this now:

struct Data {
    validUntil: Int as uint64;
    payload: Slice;
}

struct DataRaw {
    key: Int? as uint256;
    cs: Slice?;
    f: Int;
}

@name(udict_get_next?)
native mapGetNext(map: map[Int]Data, keyLen: Int, pivot: Int): DataRaw;

I also encountered the inability to determine the dimension of Int in variable and map declaration.

// Doesn't work
let key: Int as uint256 = 1;
let map: map[Int]Int = null; // impossible to create new map outside contract definition

struct Data {
  map: map[Int as uint256]Int;
}

@ex3ndr
Copy link
Contributor

ex3ndr commented Jan 28, 2023

Because it currently supports only 257 bit keys

@anstill
Copy link
Author

anstill commented Jan 31, 2023

@ex3ndr

I'm trying to extend the map, but unfortunately, the compiler does not allow me to do this.

@name(udict_get_next?)
extends native mapGetNext(self: map[Int]Int, keyLen: Int, pivot: Int): DataRaw; 
  30 | @name(udict_get_next?)
> 31 | extends native mapGetNext(self: map[Int]Int, keyLen: Int, pivot: Int): DataRaw;
                                 ^~~~~~~~~~~~~~~~~
  32 | 
Extend functions must have a reference type as the first argument

As the map represents a Cell I think it is possible to save it as a ref beginCell().storeRef(self.map).endCell().

This makes it impossible to work with map as Cell even if change declaration like this:

@name(udict_get_next?)
extends native mapGetNext(self: Cell, keyLen: Int, pivot: Int): DataRaw; 

Because there is no way to convert Map to the Cell e.g. self.map.toCell()

@ex3ndr
Copy link
Contributor

ex3ndr commented Jan 31, 2023

You can just create non-extended function, but a just native one

@anstill
Copy link
Author

anstill commented Jan 31, 2023

It doesn't work, for example

struct DataRaw {
    key: Int;
    cs: Slice;
    f: Int;
}

@name(udict_get_next?)
native mapGetNext(map: map[Int]Data, keyLen: Int, pivot: Int): DataRaw;

// ...

let nextKey: DataRaw = mapGetNext(self.data, 256, key);  // or 257

abi.dump(nextKey.f);

Any interaction with nextKey field throws a 9th exit code.

@ex3ndr
Copy link
Contributor

ex3ndr commented Jan 31, 2023

udict_get_next is for unsinged keys value, idict_get_next must be used instead with 257 bit keys.

@anstill
Copy link
Author

anstill commented Jan 31, 2023

Thanks, it's working!

@tactfunc
Copy link
Contributor

tactfunc commented Feb 1, 2023

what is this code about?

And using like native mapGetNext(map: map[Int]Data, keyLen: Int, pivot: Int): DataRaw; is a proper way to do to claim new data time like this?

@ex3ndr ex3ndr closed this as completed Feb 4, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants