diff --git a/tolk/cells.go b/tolk/cells.go index 51b34d2c..efe4a83f 100644 --- a/tolk/cells.go +++ b/tolk/cells.go @@ -66,19 +66,26 @@ func (a *Any) UnmarshalJSON(b []byte) error { return nil } -type RemainingValue boc.Cell +type RemainingValue struct { + IsRef bool + Value boc.Cell +} func (r *RemainingValue) Unmarshal(cell *boc.Cell, ty parser.Remaining, decoder *Decoder) error { rem := cell.CopyRemaining() cell.ReadRemainingBits() if rem != nil { - *r = RemainingValue(*rem) + isRef := cell.BitsAvailableForRead() == 0 && cell.RefsAvailableForRead() > 0 + *r = RemainingValue{ + IsRef: isRef, + Value: *rem, + } } return nil } func (r *RemainingValue) Marshal(cell *boc.Cell, ty parser.Remaining, encoder *Encoder) error { - c := boc.Cell(*r) + c := r.Value err := cell.WriteBitString(c.ReadRemainingBits()) if err != nil { return fmt.Errorf("failed to write remaining bits: %w", err) @@ -98,34 +105,43 @@ func (r *RemainingValue) Equal(o any) bool { if !ok { return false } - cellV := boc.Cell(*r) + cellV := r.Value vHash, err := cellV.HashString() if err != nil { return false } - cellO := boc.Cell(other) + cellO := other.Value oHash, err := cellO.HashString() if err != nil { return false } - return oHash == vHash + return oHash == vHash && r.IsRef == other.IsRef } func (r RemainingValue) MarshalJSON() ([]byte, error) { - data, err := boc.Cell(r).MarshalJSON() + cellData, err := json.Marshal(r.Value) if err != nil { - return nil, fmt.Errorf("failed to marshal remainings: %w", err) + return nil, fmt.Errorf("failed to marshal remainings data: %w", err) + } + if r.Value.BitsAvailableForRead() == 0 && r.Value.RefsAvailableForRead() == 0 { + cellData = []byte("\"\"") + } + if len(cellData) < 2 { + return nil, fmt.Errorf("invalid remaining cell data: %v", cellData) } - return data, nil -} -func (r *RemainingValue) UnmarshalJSON(b []byte) error { - v := &boc.Cell{} - if err := json.Unmarshal(b, v); err != nil { - return fmt.Errorf("failed to unmarshal remainigs: %w", err) + var jsonData = struct { + IsRef bool `json:"isRef"` + Value string `json:"value"` + }{ + IsRef: r.IsRef, + Value: string(cellData[1 : len(cellData)-1]), } - *r = RemainingValue(*v) - return nil + data, err := json.Marshal(jsonData) + if err != nil { + return nil, fmt.Errorf("failed to marshal remaining: %w", err) + } + return data, nil } type OptValue struct { diff --git a/tolk/runtime.go b/tolk/runtime.go index 5c0cdd55..2e4a4336 100644 --- a/tolk/runtime.go +++ b/tolk/runtime.go @@ -88,8 +88,11 @@ func (d *Decoder) UnmarshalMessage(cell *boc.Cell) (*Value, error) { return &res, nil } res = Value{ - SumType: "Remaining", - Remaining: (*RemainingValue)(cell), + SumType: "Remaining", + Remaining: &RemainingValue{ + IsRef: cell.BitsAvailableForRead() == 0 && cell.RefsAvailableForRead() > 0, + Value: *cell, + }, } return &res, nil } @@ -97,7 +100,7 @@ func (d *Decoder) UnmarshalMessage(cell *boc.Cell) (*Value, error) { func (d *Decoder) resolvePayload(payload *boc.Cell) (Value, bool, error) { payloadOpcode, err := payload.ReadUint(32) // payload always 32 bit length if err != nil { - return Value{}, false, fmt.Errorf("failed to read payload's opcode: %w", err) + return Value{}, false, nil } payload.ResetCounters() // reset opcode diff --git a/tolk/runtime_test.go b/tolk/runtime_test.go index 2ce2d354..caa8cd0f 100644 --- a/tolk/runtime_test.go +++ b/tolk/runtime_test.go @@ -311,7 +311,7 @@ func TestRuntime_UnmarshalRemaining(t *testing.T) { if !ok { t.Errorf("v.GetCell() not successeded") } - hs, err := val.HashString() + hs, err := val.Value.HashString() if err != nil { t.Fatal(err) } @@ -2340,7 +2340,7 @@ func TestRuntime_UnmarshalStructWithDefaultValues(t *testing.T) { if !ok { t.Fatalf("currStruct[slice3].GetRemaining() not successeded") } - hs, err := slice3Val.HashString() + hs, err := slice3Val.Value.HashString() if err != nil { t.Fatal(err) } diff --git a/tolk/testdata/json/a_lot_generics_with_default_values.json b/tolk/testdata/json/a_lot_generics_with_default_values.json index a54dc88b..0ff7a93c 100755 --- a/tolk/testdata/json/a_lot_generics_with_default_values.json +++ b/tolk/testdata/json/a_lot_generics_with_default_values.json @@ -22,7 +22,10 @@ }, "slice3": { "isExists": true, - "value": "b5ee9c72010101010005000006616263" + "value": { + "isRef": false, + "value": "b5ee9c72010101010005000006616263" + } } } } \ No newline at end of file diff --git a/tolk/testdata/json/remaining.json b/tolk/testdata/json/remaining.json index 8285abe4..3e566160 100755 --- a/tolk/testdata/json/remaining.json +++ b/tolk/testdata/json/remaining.json @@ -1,3 +1,6 @@ { - "value": "b5ee9c7201010101000900000dc0800000000ab8" + "value": { + "isRef": false, + "value": "b5ee9c7201010101000900000dc0800000000ab8" + } } \ No newline at end of file diff --git a/tolk/value.go b/tolk/value.go index 488796d0..75516459 100644 --- a/tolk/value.go +++ b/tolk/value.go @@ -394,18 +394,18 @@ func (v *Value) MustGetCell() boc.Cell { return boc.Cell(*v.Cell) } -func (v *Value) GetRemaining() (boc.Cell, bool) { +func (v *Value) GetRemaining() (RemainingValue, bool) { if v.Remaining == nil { - return boc.Cell{}, false + return RemainingValue{}, false } - return boc.Cell(*v.Remaining), true + return *v.Remaining, true } -func (v *Value) MustGetRemaining() boc.Cell { +func (v *Value) MustGetRemaining() RemainingValue { if v.Remaining == nil { panic("value is not a remaining") } - return boc.Cell(*v.Remaining) + return *v.Remaining } func (v *Value) GetType() string {