Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
474 changes: 237 additions & 237 deletions abi/get_methods.go

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions abi/parser/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,15 @@ func buildInputStackValues(r []StackRecord) string {

func buildOutputStackCheck(r []StackRecord, isFixed bool) string {
var builder strings.Builder
n := len(r)
if isFixed {
builder.WriteString(fmt.Sprintf("if len(stack) != %d ", len(r)))
builder.WriteString(fmt.Sprintf("if stack.Len() != %d ", n))
} else {
builder.WriteString(fmt.Sprintf("if len(stack) < %d ", len(r)))
builder.WriteString(fmt.Sprintf("if stack.Len() < %d ", n))
}
for i, s := range r {
nullableCheck := ""
stackType := fmt.Sprintf("stack[%d].SumType", i)
stackType := fmt.Sprintf("stack.Peek(%d).SumType", n-1-i)
if s.Nullable || (s.XMLName.Local == "tuple" && s.List) {
nullableCheck = fmt.Sprintf(" && %s != \"VmStkNull\"", stackType)
}
Expand Down
10 changes: 5 additions & 5 deletions contract/dns/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ func (d *DNS) Resolve(ctx context.Context, domain string) (map[DNSCategory]tlb.D

func (d *DNS) resolve(ctx context.Context, resolver ton.AccountID, dom []byte) (map[DNSCategory]tlb.DNSRecord, error) {
n := int64(len(dom))
stack := tlb.VmStack{}
argStack := tlb.VmStack{}
val, err := tlb.TlbStructToVmCellSlice(dom)
if err != nil {
return nil, err
}
stack.Put(val)
stack.Put(tlb.VmStackValue{SumType: "VmStkInt", VmStkInt: tlb.Int257{}})
exitCode, stack, err := d.executor.RunSmcMethodByID(ctx, resolver, 123660, stack)
argStack.Put(val)
argStack.Put(tlb.VmStackValue{SumType: "VmStkInt", VmStkInt: tlb.Int257{}})
exitCode, stack, err := d.executor.RunSmcMethodByID(ctx, resolver, 123660, argStack)
if err != nil && strings.Contains(err.Error(), "method execution failed") {
return nil, fmt.Errorf("%w: %v", ErrNotResolved, err)
}
Expand All @@ -86,7 +86,7 @@ func (d *DNS) resolve(ctx context.Context, resolver ton.AccountID, dom []byte) (
ResolvedBits int64
Result boc.Cell
}
if len(stack) == 2 && stack[0].SumType == "VmStkTinyInt" && stack[0].VmStkTinyInt == 0 && stack[1].SumType == "VmStkNull" {
if stack.Len() == 2 && stack.Peek(1).SumType == "VmStkTinyInt" && stack.Peek(1).VmStkTinyInt == 0 && stack.Peek(0).SumType == "VmStkNull" {
return nil, ErrNotResolved
}
err = stack.Unmarshal(&result)
Expand Down
6 changes: 3 additions & 3 deletions examples/tvm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func main() {
panic(err)
}

code, res, err := emulator.RunSmcMethod(context.Background(), account.ID, "get_nft_address_by_index", tlb.VmStack{val})
code, res, err := emulator.RunSmcMethod(context.Background(), account.ID, "get_nft_address_by_index", val.ToStack())
if err != nil {
panic(err)
}
Expand All @@ -46,11 +46,11 @@ func main() {
panic("TVM execution failed")
}

if len(res) != 1 || res[0].SumType != "VmStkSlice" {
if res.Len() != 1 || res.Peek(0).SumType != "VmStkSlice" {
panic("invalid stack data")
}

c := res[0].VmStkSlice.Cell()
c := res.Peek(0).VmStkSlice.Cell()
var a tlb.MsgAddress
err = tlb.Unmarshal(c, &a)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion liteapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ func (c *Client) RunSmcMethodByID(ctx context.Context, accountID ton.AccountID,
}
var result tlb.VmStack
if res.ExitCode == 4294967040 { //-256
return res.ExitCode, nil, ErrAccountNotFound
return res.ExitCode, tlb.VmStack{}, ErrAccountNotFound
}
cells, err := boc.DeserializeBoc(res.Result)
if err != nil {
Expand Down
11 changes: 6 additions & 5 deletions liteapi/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,16 @@ func (c *Client) DnsResolve(ctx context.Context, address ton.AccountID, domain s
if errCode != 0 && errCode != 1 {
return 0, nil, fmt.Errorf("method execution failed with code: %v", errCode)
}
if len(stack) != 2 ||
stack[0].SumType != "VmStkTinyInt" ||
(stack[1].SumType != "VmStkCell" && stack[1].SumType != "VmStkNull") {
if stack.Len() != 2 ||
stack.Peek(1).SumType != "VmStkTinyInt" ||
(stack.Peek(0).SumType != "VmStkCell" && stack.Peek(0).SumType != "VmStkNull") {
return 0, nil, fmt.Errorf("invalid stack")
}
if stack[1].SumType == "VmStkNull" {
if stack.Peek(0).SumType == "VmStkNull" {
return 0, nil, nil
}
return int(stack[0].VmStkTinyInt), &stack[1].VmStkCell.Value, err
topVal := stack.Peek(0).VmStkCell.Value
return int(stack.Peek(1).VmStkTinyInt), &topVal, err
}

func (c *Client) GetRootDNS(ctx context.Context) (ton.AccountID, error) {
Expand Down
34 changes: 18 additions & 16 deletions liteapi/jetton.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ func (c *Client) GetJettonWallet(ctx context.Context, master, owner ton.AccountI
if err != nil {
return ton.AccountID{}, err
}
errCode, stack, err := c.RunSmcMethod(ctx, master, "get_wallet_address", tlb.VmStack{val})
errCode, stack, err := c.RunSmcMethod(ctx, master, "get_wallet_address", val.ToStack())
if err != nil {
return ton.AccountID{}, err
}
if errCode != 0 && errCode != 1 {
return ton.AccountID{}, fmt.Errorf("method execution failed with code: %v", errCode)
}
if len(stack) != 1 || stack[0].SumType != "VmStkSlice" {
if stack.Len() != 1 || stack.Peek(0).SumType != "VmStkSlice" {
return ton.AccountID{}, fmt.Errorf("invalid stack")
}
var res tlb.MsgAddress
err = stack[0].VmStkSlice.UnmarshalToTlbStruct(&res)
err = stack.Peek(0).VmStkSlice.UnmarshalToTlbStruct(&res)
if err != nil {
return ton.AccountID{}, err
}
Expand All @@ -58,14 +58,15 @@ func (c *Client) GetJettonData(ctx context.Context, master ton.AccountID) (tep64
if errCode != 0 && errCode != 1 {
return tep64.Metadata{}, fmt.Errorf("method execution failed with code: %v", errCode)
}
if len(stack) != 5 || (stack[0].SumType != "VmStkTinyInt" && stack[0].SumType != "VmStkInt") ||
stack[1].SumType != "VmStkTinyInt" ||
stack[2].SumType != "VmStkSlice" ||
stack[3].SumType != "VmStkCell" ||
stack[4].SumType != "VmStkCell" {
if stack.Len() != 5 || (stack.Peek(4).SumType != "VmStkTinyInt" && stack.Peek(4).SumType != "VmStkInt") ||
stack.Peek(3).SumType != "VmStkTinyInt" ||
stack.Peek(2).SumType != "VmStkSlice" ||
stack.Peek(1).SumType != "VmStkCell" ||
stack.Peek(0).SumType != "VmStkCell" {
return tep64.Metadata{}, fmt.Errorf("invalid stack")
}
cell := &stack[3].VmStkCell.Value
elem1 := stack.Peek(1)
cell := &elem1.VmStkCell.Value
var content tlb.FullContent
err = tlb.Unmarshal(cell, &content)
if err != nil {
Expand Down Expand Up @@ -95,15 +96,16 @@ func (c *Client) GetJettonBalance(ctx context.Context, jettonWallet ton.AccountI
if errCode != 0 && errCode != 1 {
return nil, fmt.Errorf("method execution failed with code: %v", errCode)
}
if len(stack) != 4 || (stack[0].SumType != "VmStkTinyInt" && stack[0].SumType != "VmStkInt") ||
stack[1].SumType != "VmStkSlice" ||
stack[2].SumType != "VmStkSlice" ||
stack[3].SumType != "VmStkCell" {
if stack.Len() != 4 || (stack.Peek(3).SumType != "VmStkTinyInt" && stack.Peek(3).SumType != "VmStkInt") ||
stack.Peek(2).SumType != "VmStkSlice" ||
stack.Peek(1).SumType != "VmStkSlice" ||
stack.Peek(0).SumType != "VmStkCell" {
return nil, fmt.Errorf("invalid stack")
}
if stack[0].SumType == "VmStkTinyInt" {
return big.NewInt(stack[0].VmStkTinyInt), nil
bottom := stack.Peek(3)
if bottom.SumType == "VmStkTinyInt" {
return big.NewInt(bottom.VmStkTinyInt), nil
}
res := big.Int(stack[0].VmStkInt)
res := big.Int(bottom.VmStkInt)
return &res, nil
}
4 changes: 2 additions & 2 deletions liteapi/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ func (c *Client) GetSeqno(ctx context.Context, account ton.AccountID) (uint32, e
} else if errCode != 0 && errCode != 1 {
return 0, fmt.Errorf("method execution failed with code: %v", errCode)
}
if len(stack) != 1 || stack[0].SumType != "VmStkTinyInt" {
if stack.Len() != 1 || stack.Peek(0).SumType != "VmStkTinyInt" {
return 0, fmt.Errorf("invalid stack")
}
return uint32(stack[0].VmStkTinyInt), nil
return uint32(stack.Peek(0).VmStkTinyInt), nil
}
117 changes: 101 additions & 16 deletions tlb/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,25 @@ import (
// vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack;
// vm_stk_cons#_ {n:#} rest:^(VmStackList n) tos:VmStackValue = VmStackList (n + 1);
// vm_stk_nil#_ = VmStackList 0;
type VmStack []VmStackValue
type VmStack struct {
values []VmStackValue // last element is top of the stack
}

// Len returns the size of the stack
func (s VmStack) Len() int {
return len(s.values)
}

// Peek returns the top element from the stack (if i == 0) without popping it out
// peeking empty stack will panic as out of range
func (s VmStack) Peek(i int) VmStackValue {
return s.values[len(s.values)-i-1]
}

// Put puts the value on top of the stack
func (s *VmStack) Put(val VmStackValue) {
s.values = append(s.values, val)
}

// VmCont
// _ cregs:(HashmapE 4 VmStackValue) = VmSaveList;
Expand Down Expand Up @@ -61,8 +79,74 @@ type VmTupleRef struct {
}

func (t VmStkTuple) MarshalTLB(c *boc.Cell, encoder *Encoder) error {
// TODO: implement
return fmt.Errorf("VmStkTuple TLB marshaling not implemented")
if err := c.WriteUint(uint64(t.Len), 16); err != nil {
return err
}
if t.Len == 0 {
if t.Data != nil {
return fmt.Errorf("tuple data must be nil when len is 0")
}
return nil
}
if t.Data == nil {
return fmt.Errorf("tuple data is nil for len %d", t.Len)
}
return marshalVmTuple(c, t.Len, t.Data, encoder)
}

func marshalVmTuple(c *boc.Cell, length uint16, tuple *VmTuple, encoder *Encoder) error {
if length == 0 {
if tuple != nil {
return fmt.Errorf("unexpected tuple payload for len 0")
}
return nil
}
if tuple == nil {
return fmt.Errorf("tuple is nil for len %d", length)
}
n := length - 1
if err := marshalVmTupleRef(c, n, &tuple.Head, encoder); err != nil {
return err
}
if n == 0 {
return nil
}
if tuple.Tail.SumType == "" {
return fmt.Errorf("tuple tail is empty for len %d", length)
}
ref, err := c.NewRef()
if err != nil {
return err
}
return encoder.Marshal(ref, tuple.Tail)
}

func marshalVmTupleRef(c *boc.Cell, n uint16, ref *VmTupleRef, encoder *Encoder) error {
if ref == nil {
return fmt.Errorf("tuple ref is nil")
}
switch {
case n == 0 || n == 1:
if ref.Entry == nil {
return fmt.Errorf("tuple ref entry is nil for n=%d", n)
}
entryCell, err := c.NewRef()
if err != nil {
return err
}
return encoder.Marshal(entryCell, ref.Entry)
case n > 1:
if ref.Ref == nil {
return fmt.Errorf("tuple ref child is nil for n=%d", n)
}
childCell, err := c.NewRef()
if err != nil {
return err
}
return marshalVmTuple(childCell, n, ref.Ref, encoder)
default:
return fmt.Errorf("unsupported tuple ref size n=%d", n)
}
}

func (t *VmStkTuple) UnmarshalTLB(c *boc.Cell, decoder *Decoder) error {
Expand Down Expand Up @@ -170,13 +254,17 @@ type VmStackValue struct {
VmStkTuple VmStkTuple `tlbSumType:"vm_stk_tuple#07"`
}

func (v VmStackValue) ToStack() VmStack {
return VmStack{values: []VmStackValue{v}}
}

func (s VmStack) MarshalTLB(c *boc.Cell, encoder *Encoder) error {
depth := uint64(len(s))
depth := uint64(len(s.values))
err := c.WriteUint(depth, 24)
if err != nil {
return err
}
err = putStackListItems(c, s)
err = putStackListItems(c, s.values)
return err
}

Expand All @@ -192,7 +280,7 @@ func (s *VmStack) UnmarshalTLB(c *boc.Cell, decoder *Decoder) error {
if err != nil {
return err
}
*s = list
s.values = list
return nil
}

Expand Down Expand Up @@ -222,19 +310,20 @@ func getStackListItems(c *boc.Cell, depth uint64, decoder *Decoder) ([]VmStackVa
}

func putStackListItems(c *boc.Cell, list []VmStackValue) error {
if len(list) == 0 {
llen := len(list)
if llen == 0 {
return nil
}
restCell := boc.NewCell()
err := putStackListItems(restCell, list[1:])
err := putStackListItems(restCell, list[:llen-1]) // llen 1 -> list[0:0]
if err != nil {
return err
}
err = c.AddRef(restCell)
if err != nil {
return err
}
err = Marshal(c, list[0])
err = Marshal(c, list[llen-1]) // llen 1 -> list[0]
return err
}

Expand Down Expand Up @@ -267,10 +356,6 @@ func (s *VmStack) UnmarshalTL(r io.Reader) error {
return Unmarshal(cell[0], s)
}

func (s *VmStack) Put(val VmStackValue) {
*s = append(VmStack{val}, *s...)
}

func (s VmCellSlice) MarshalTLB(c *boc.Cell, encoder *Encoder) error {
if s.stBits > s.endBits {
return fmt.Errorf("invalid StBits and EndBits for CellSlice")
Expand Down Expand Up @@ -617,20 +702,20 @@ func (s VmStack) Unmarshal(dest any) error {
if val.Kind() != reflect.Pointer {
return fmt.Errorf("value should be a pointer")
}
if val.Elem().Type().NumField() > len(s) {
if val.Elem().Type().NumField() > len(s.values) {
return fmt.Errorf("not enough values in stack")
}
for i := 0; i < val.Elem().Type().NumField(); i++ {
fieldType := val.Elem().Field(i).Type()
if s[i].SumType == "VmStkNull" {
if s.values[i].SumType == "VmStkNull" {
kind := fieldType.Kind()
if kind == reflect.Pointer || kind == reflect.Slice {
continue
}
return errors.New("can't unmarshal null")
}
value := reflect.New(fieldType)
if err := s[i].Unmarshal(value.Interface()); err != nil {
if err := s.values[i].Unmarshal(value.Interface()); err != nil {
return err
}
val.Elem().Field(i).Set(value.Elem())
Expand Down
2 changes: 1 addition & 1 deletion tlb/stack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func Test_IntMatrixTupleUnmarshal(t *testing.T) {
if err != nil {
t.Fatal(err)
}
val := stack[0]
val := stack.Peek(0)
if val.SumType != "VmStkTuple" {
t.Errorf("Stack value must be tuple, got %v", val.SumType)
}
Expand Down
Loading
Loading