diff --git a/go.mod b/go.mod index 727a9b34..0155027e 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/tonkeeper/tongo go 1.19 require ( + github.com/alecthomas/assert/v2 v2.0.3 github.com/alecthomas/participle/v2 v2.0.0-beta.5 github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae github.com/snksoft/crc v1.1.0 @@ -12,5 +13,6 @@ require ( require ( github.com/alecthomas/repr v0.1.1 // indirect + github.com/hexops/gotextdiff v1.0.3 // indirect golang.org/x/sys v0.15.0 // indirect ) diff --git a/go.sum b/go.sum index 53ea4109..f22b3b91 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,11 @@ github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg= +github.com/alecthomas/assert/v2 v2.0.3/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA= github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo= github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM= github.com/alecthomas/repr v0.1.1 h1:87P60cSmareLAxMc4Hro0r2RBY4ROm0dYwkJNpS4pPs= github.com/alecthomas/repr v0.1.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae h1:7smdlrfdcZic4VfsGKD2ulWL804a4GVphr4s7WZxGiY= github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/snksoft/crc v1.1.0 h1:HkLdI4taFlgGGG1KvsWMpz78PkOC9TkPVpTV/cuWn48= diff --git a/tlb/decoder.go b/tlb/decoder.go index d3812629..de8f46c4 100644 --- a/tlb/decoder.go +++ b/tlb/decoder.go @@ -55,6 +55,35 @@ func Unmarshal(c *boc.Cell, o any) error { return decode(c, "", reflect.ValueOf(o), &dec) } +// UnmarshalMessage decodes the given cell using TL-B schema and stores the result in the value pointed to by o. +func UnmarshalMessage(c *boc.Cell, o any) (opCode uint32, err error) { + // create a new struct with OpCode and Data fields + newStructType := reflect.StructOf([]reflect.StructField{ + { + Name: "OpCode", + Type: reflect.TypeOf(opCode), + }, + { + Name: "Data", + Type: reflect.TypeOf(o).Elem(), + }, + }) + + newStructPtr := reflect.New(newStructType) + newStruct := newStructPtr.Elem() + newStruct.Field(1).Set(reflect.ValueOf(o).Elem()) + // unmarshal the cell into the new struct + err = Unmarshal(c, newStruct.Addr().Interface()) + if err != nil { + return + } + // set the OpCode and Data fields to the original struct + opCode = uint32(newStruct.Field(0).Uint()) + reflect.ValueOf(o).Elem().Set(newStruct.Field(1)) + + return +} + var bocCellType = reflect.TypeOf(boc.Cell{}) var bocCellPointerType = reflect.TypeOf(&boc.Cell{}) var bocTlbANyPointerType = reflect.TypeOf(&Any{}) diff --git a/tlb/decoder_test.go b/tlb/decoder_test.go new file mode 100644 index 00000000..4186a641 --- /dev/null +++ b/tlb/decoder_test.go @@ -0,0 +1,65 @@ +package tlb + +import ( + "fmt" + "testing" + + "github.com/alecthomas/assert/v2" + "github.com/tonkeeper/tongo/boc" +) + +func Test_UnmarshalMessage(t *testing.T) { + rawBody := "b5ee9c7201010101000e000018d53276db546de4efe9d175f0" + ex, err := newParseTokenExcesses(rawBody) + assert.NoError(t, err) + t.Logf("%+v", ex) + ex1, err := parseTokenExcesses(rawBody) + assert.Equal(t, ex1.QueryId, ex.QueryId) +} + +type TokenExcesses struct { + QueryId uint64 +} + +func newParseTokenExcesses(rawBody string) (*TokenExcesses, error) { + cells, err := boc.DeserializeBocHex(rawBody) + if err != nil { + return nil, err + } + ex := TokenExcesses{} + opCode, err := UnmarshalMessage(cells[0], &ex) + if err != nil { + return nil, err + } + if opCode != uint32(0xd53276db) { + return nil, fmt.Errorf("unexpected opCode: %x", opCode) + } + //return struct without opCode + return &ex, nil +} + +type TokenExcessesWithOpCode struct { + OpCode uint32 + QueryId uint64 +} + +func parseTokenExcesses(rawBody string) (*TokenExcesses, error) { + cells, err := boc.DeserializeBocHex(rawBody) + if err != nil { + return nil, err + } + //define new struct with opCode + ex := TokenExcessesWithOpCode{} + err = Unmarshal(cells[0], &ex) + if err != nil { + return nil, err + } + //return struct without opCode + return &TokenExcesses{QueryId: ex.QueryId}, nil +} +func Test_Unmarshal(t *testing.T) { + rawBody := "b5ee9c7201010101000e000018d53276db546de4efe9d175f0" + ex, err := parseTokenExcesses(rawBody) + assert.NoError(t, err) + t.Logf("%+v", ex) +}