Skip to content

Commit 7fdfd97

Browse files
committed
Extract opcode from tlb tags
1 parent c5046f5 commit 7fdfd97

File tree

9 files changed

+117
-77
lines changed

9 files changed

+117
-77
lines changed

pkg/ccip/bindings/feequoter/fee_quoter.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,9 @@ type UpdateTokenTransferFeeConfig struct {
289289
Add map[*address.Address]TokenTransferFeeConfig
290290
Remove []*address.Address `tlb:"addr"`
291291
}
292-
type UpdateTokenTransferFeeConfigs struct{}
292+
type UpdateTokenTransferFeeConfigs struct {
293+
_ tlb.Magic `tlb:"#B2826316"` //nolint:revive // Ignore opcode tag
294+
}
293295

294296
type UpdateDestChainConfig struct {
295297
DestinationChainSelector uint64 `tlb:"## 64"`

pkg/ton/debug/decoders/ccip/ccipsendexecutor/ccipsendexecutor.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@ import (
1212
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
1313
)
1414

15-
// TODO: auto-generate this map from a set of msgs using TL-B tag to read opcodes
16-
var TLBs = map[int]interface{}{
17-
ccipsendexecutor.OpcodeCCIPSendExecutorExecute: ccipsendexecutor.Execute{},
15+
var TLBs = lib.MustNewTLBMap([]interface{}{
16+
ccipsendexecutor.Execute{},
1817

1918
// Note: We don't handle JettonTransferNotification or FeeQuoter_MessageValidated here
2019
// because they are already handled by their respective decoders (jetton wallet and fee quoter)
21-
}
20+
})
2221

2322
type decoder struct {
2423
payloadDecoders map[cldf.ContractType]lib.ContractDecoder

pkg/ton/debug/decoders/ccip/feequoter/feequoter.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,14 @@ import (
1212
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
1313
)
1414

15-
// TODO: auto-generate this map from a set of msgs using TL-B tag to read opcodes
16-
var TLBs = map[int]interface{}{
17-
feequoter.OpcodeUpdatePrices: feequoter.UpdatePrices{},
18-
feequoter.OpcodeUpdateFeeTokens: feequoter.UpdateFeeTokens{},
19-
feequoter.OpcodeUpdateTokenTransferFeeConfigs: feequoter.UpdateTokenTransferFeeConfigs{},
20-
feequoter.OpcodeUpdateDestChainConfigs: feequoter.UpdateDestChainConfigs{},
21-
feequoter.OpcodeFeeQuoterGetValidatedFee: feequoter.GetValidatedFee{},
22-
feequoter.OpcodeFeeQuoterMessageValidated: feequoter.MessageValidated{},
23-
}
15+
var TLBs = lib.MustNewTLBMap([]interface{}{
16+
feequoter.UpdatePrices{},
17+
feequoter.UpdateFeeTokens{},
18+
feequoter.UpdateTokenTransferFeeConfigs{},
19+
feequoter.UpdateDestChainConfigs{},
20+
feequoter.GetValidatedFee{},
21+
feequoter.MessageValidated{},
22+
})
2423

2524
type decoder struct {
2625
}

pkg/ton/debug/decoders/ccip/onramp/onramp.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@ import (
1515
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
1616
)
1717

18-
// TODO: auto-generate this map from a set of msgs using TL-B tag to read opcodes
19-
var TLBs = map[int]interface{}{
20-
onramp.OpcodeOnRampSend: onramp.Send{},
21-
onramp.OpcodeOnRampWithdrawJettons: onramp.WithdrawJettons{},
22-
onramp.OpcodeOnRampExecutorFinishedSuccessfully: onramp.ExecutorFinishedSuccessfully{},
23-
onramp.OpcodeSetDynamicConfig: onramp.SetDynamicConfigMessage{},
24-
onramp.OpcodeUpdateDestChainConfigs: onramp.UpdateDestChainConfigsMessage{},
25-
onramp.OpcodeUpdateAllowlists: onramp.UpdateAllowlistsMessage{},
26-
}
18+
var TLBs = lib.MustNewTLBMap([]interface{}{
19+
onramp.Send{},
20+
onramp.WithdrawJettons{},
21+
onramp.ExecutorFinishedSuccessfully{},
22+
onramp.SetDynamicConfigMessage{},
23+
onramp.UpdateDestChainConfigsMessage{},
24+
onramp.UpdateAllowlistsMessage{},
25+
})
2726

2827
type decoder struct {
2928
payloadDecoders map[cldf.ContractType]lib.ContractDecoder

pkg/ton/debug/decoders/ccip/router/router.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ import (
1212
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
1313
)
1414

15-
// TODO: auto-generate this map from a set of msgs using TL-B tag to read opcodes
16-
var TLBs = map[int]interface{}{
17-
router.OpcodeSetRamps: router.SetRamps{},
18-
router.OpcodeCCIPSend: router.CCIPSend{},
19-
}
15+
var TLBs = lib.MustNewTLBMap([]interface{}{
16+
router.SetRamps{},
17+
router.CCIPSend{},
18+
})
2019

2120
type decoder struct {
2221
payloadDecoders map[cldf.ContractType]lib.ContractDecoder

pkg/ton/debug/decoders/jetton/common.go

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,33 @@
11
package jetton
22

33
import (
4-
"github.com/xssnick/tonutils-go/tlb"
54
"github.com/xssnick/tonutils-go/tvm/cell"
65

6+
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
77
"github.com/smartcontractkit/chainlink-ton/pkg/bindings/jetton"
88

99
"github.com/smartcontractkit/chainlink-ton/pkg/ton/debug/lib"
1010
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
1111
)
1212

13+
var TLBs = lib.MustNewTLBMap([]interface{}{
14+
jetton.TopUpMessage{},
15+
})
16+
1317
type decoder struct {
18+
contractType cldf.ContractType
1419
}
1520

16-
func NewDecoder() *decoder {
17-
return &decoder{}
21+
func NewDecoder(t cldf.ContractType) *decoder {
22+
return &decoder{contractType: t}
1823
}
1924

2025
// InternalMessageInfo implements lib.ContractDecoder.
21-
func (j *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
22-
r := msg.BeginParse()
23-
if r.BitsLeft() == 0 {
24-
return nil, &lib.UnknownMessageError{}
25-
}
26-
opCode, err := r.PreloadUInt(32)
27-
if err != nil {
28-
return nil, err
29-
}
30-
if opCode == jetton.OpcodeTopUp {
31-
var topUp jetton.TopUpMessage
32-
err := tlb.LoadFromCell(&topUp, r)
33-
if err != nil {
34-
return nil, err
35-
}
36-
return lib.NewMessageInfo("TopUp", topUp)
37-
}
38-
return nil, &lib.UnknownMessageError{}
26+
func (d *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
27+
return lib.NewMessageInfoFromCell(d.contractType, msg, TLBs)
3928
}
4029

41-
func (j *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
30+
func (d *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
4231
switch exitCode {
4332
case jetton.ErrorInvalidOp:
4433
return "ErrorInvalidOp", nil

pkg/ton/debug/decoders/jetton/minter/jetton_minter.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,22 @@ func NewDecoder(payloadDecoders map[cldf.ContractType]lib.ContractDecoder) lib.C
2626
}
2727

2828
// ContractType implements lib.ContractDecoder.
29-
func (j *decoder) ContractType() cldf.ContractType {
29+
func (d *decoder) ContractType() cldf.ContractType {
3030
return cldf.ContractType("com.github.ton-blockchain.jetton-contract.contracts.jetton-minter")
3131
}
3232

3333
// EventInfo implements lib.ContractDecoder.
34-
func (j *decoder) EventInfo(dstAddr *address.Address, msg *cell.Cell) (lib.MessageInfo, error) {
34+
func (d *decoder) EventInfo(dstAddr *address.Address, msg *cell.Cell) (lib.MessageInfo, error) {
3535
return nil, &lib.UnknownMessageError{}
3636
}
3737

3838
// ExternalMessageInfo implements lib.ContractDecoder.
39-
func (j *decoder) ExternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
39+
func (d *decoder) ExternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
4040
return nil, &lib.UnknownMessageError{}
4141
}
4242

4343
// InternalMessageInfo implements lib.ContractDecoder.
44-
func (j *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
44+
func (d *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
4545
r := msg.BeginParse()
4646
if r.BitsLeft() == 0 {
4747
return nil, &lib.UnknownMessageError{}
@@ -61,7 +61,7 @@ func (j *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
6161
return lib.NewMessageInfo("Mint", mint)
6262
}
6363

64-
payloadInfo, err := j.tryDecodePayload(mint.MasterMsg.ForwardPayload)
64+
payloadInfo, err := d.tryDecodePayload(mint.MasterMsg.ForwardPayload)
6565
if err != nil {
6666
return nil, err
6767
}
@@ -87,12 +87,12 @@ func (j *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
8787
return lib.NewMessageInfo("ClaimAdmin", changeContent)
8888
// TODO missing messages
8989
}
90-
return jetton.NewDecoder().InternalMessageInfo(msg)
90+
return jetton.NewDecoder(d.ContractType()).InternalMessageInfo(msg)
9191
}
9292

93-
func (j *decoder) tryDecodePayload(payloadCell *cell.Cell) (lib.MessageInfo, error) {
94-
for _, d := range j.payloadDecoders {
95-
info, err := d.InternalMessageInfo(payloadCell)
93+
func (d *decoder) tryDecodePayload(payloadCell *cell.Cell) (lib.MessageInfo, error) {
94+
for _, pd := range d.payloadDecoders {
95+
info, err := pd.InternalMessageInfo(payloadCell)
9696
if err == nil {
9797
return info, nil
9898
}
@@ -110,6 +110,6 @@ type MintMessageDescription struct {
110110
MasterMsg wallet.InternalTransferMessageDescription
111111
}
112112

113-
func (j *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
114-
return jetton.NewDecoder().ExitCodeInfo(exitCode)
113+
func (d *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
114+
return jetton.NewDecoder(d.ContractType()).ExitCodeInfo(exitCode)
115115
}

pkg/ton/debug/decoders/jetton/wallet/jetton_wallet.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ func NewDecoder(payloadDecoders map[cldf.ContractType]lib.ContractDecoder) lib.C
2525
}
2626

2727
// ContractType implements lib.ContractDecoder.
28-
func (j *decoder) ContractType() cldf.ContractType {
28+
func (d *decoder) ContractType() cldf.ContractType {
2929
return cldf.ContractType("com.github.ton-blockchain.jetton-contract.contracts.jetton-wallet")
3030
}
3131

3232
// EventInfo implements lib.ContractDecoder.
33-
func (j *decoder) EventInfo(dstAddr *address.Address, msg *cell.Cell) (lib.MessageInfo, error) {
33+
func (d *decoder) EventInfo(dstAddr *address.Address, msg *cell.Cell) (lib.MessageInfo, error) {
3434
return nil, &lib.UnknownMessageError{}
3535
}
3636

3737
// ExternalMessageInfo implements lib.ContractDecoder.
38-
func (j *decoder) ExternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
38+
func (d *decoder) ExternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
3939
return nil, &lib.UnknownMessageError{}
4040
}
4141

4242
// InternalMessageInfo implements lib.ContractDecoder.
43-
func (j *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
43+
func (d *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
4444
r := msg.BeginParse()
4545
if r.BitsLeft() == 0 {
4646
return nil, &lib.UnknownMessageError{}
@@ -60,7 +60,7 @@ func (j *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
6060
return lib.NewMessageInfo("AskToTransfer", askToTransfer)
6161
}
6262

63-
payloadInfo, err := j.tryDecodePayload(askToTransfer.CustomPayload)
63+
payloadInfo, err := d.tryDecodePayload(askToTransfer.CustomPayload)
6464
if err == nil {
6565
return lib.NewMessageInfo("AskToTransferWithPayload", AskToTransferMessageDescription{
6666
QueryID: askToTransfer.QueryID,
@@ -82,12 +82,12 @@ func (j *decoder) InternalMessageInfo(msg *cell.Cell) (lib.MessageInfo, error) {
8282
return lib.NewMessageInfo("InternalTransfer", internalTransfer)
8383
}
8484

85-
payloadInfo, err := j.tryDecodePayload(internalTransfer.ForwardPayload)
85+
payloadInfo, err := d.tryDecodePayload(internalTransfer.ForwardPayload)
8686
if err == nil {
8787
return lib.NewMessageInfo("InternalTransferWithPayload", InternalTransferDescription(internalTransfer, payloadInfo))
8888
}
8989
}
90-
return jetton_common.NewDecoder().InternalMessageInfo(msg)
90+
return jetton_common.NewDecoder(d.ContractType()).InternalMessageInfo(msg)
9191
}
9292

9393
func InternalTransferDescription(internalTransfer wallet.InternalTransferMessage, payloadInfo lib.MessageInfo) InternalTransferMessageDescription {
@@ -101,9 +101,9 @@ func InternalTransferDescription(internalTransfer wallet.InternalTransferMessage
101101
}
102102
}
103103

104-
func (j *decoder) tryDecodePayload(payloadCell *cell.Cell) (lib.MessageInfo, error) {
105-
for _, d := range j.payloadDecoders {
106-
info, err := d.InternalMessageInfo(payloadCell)
104+
func (d *decoder) tryDecodePayload(payloadCell *cell.Cell) (lib.MessageInfo, error) {
105+
for _, pd := range d.payloadDecoders {
106+
info, err := pd.InternalMessageInfo(payloadCell)
107107
if err == nil {
108108
return info, nil
109109
}
@@ -133,7 +133,7 @@ type InternalTransferMessageDescription struct {
133133
ForwardPayload any
134134
}
135135

136-
func (j *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
136+
func (d *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
137137
switch exitCode {
138138
case wallet.BalanceError:
139139
return "BalanceError", nil
@@ -142,6 +142,6 @@ func (j *decoder) ExitCodeInfo(exitCode tvm.ExitCode) (string, error) {
142142
case wallet.InvalidMessage:
143143
return "InvalidMessage", nil
144144
default:
145-
return jetton_common.NewDecoder().ExitCodeInfo(exitCode)
145+
return jetton_common.NewDecoder(d.ContractType()).ExitCodeInfo(exitCode)
146146
}
147147
}

pkg/ton/debug/lib/lib.go

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"encoding/json"
55
"fmt"
66
"reflect"
7+
"strconv"
8+
"strings"
79

810
"github.com/xssnick/tonutils-go/address"
911
"github.com/xssnick/tonutils-go/tlb"
@@ -51,7 +53,7 @@ type ContractDecoder interface {
5153
ExitCodeInfo(exitCode tvm.ExitCode) (string, error)
5254
}
5355

54-
func NewMessageInfo[T any](name string, msg T) (MessageInfo, error) {
56+
func NewMessageInfo(name string, msg any) (MessageInfo, error) {
5557
short, err := json.Marshal(msg)
5658
if err != nil {
5759
return nil, err
@@ -68,7 +70,7 @@ func NewMessageInfo[T any](name string, msg T) (MessageInfo, error) {
6870
}
6971

7072
// NewMessageInfoFromCell attempts to decode the given cell using the provided TL-B candidates mapped by their opcodes.
71-
func NewMessageInfoFromCell(t cldf.ContractType, msg *cell.Cell, tlbs map[int]interface{}) (MessageInfo, error) {
73+
func NewMessageInfoFromCell(t cldf.ContractType, msg *cell.Cell, tlbs map[uint64]interface{}) (MessageInfo, error) {
7274
r := msg.BeginParse()
7375
if r.BitsLeft() == 0 {
7476
return nil, &UnknownMessageError{}
@@ -78,7 +80,7 @@ func NewMessageInfoFromCell(t cldf.ContractType, msg *cell.Cell, tlbs map[int]in
7880
return nil, fmt.Errorf("failed to preload opcode: %w", err)
7981
}
8082

81-
i, ok := tlbs[int(opCode)]
83+
i, ok := tlbs[opCode]
8284
if !ok {
8385
return nil, &UnknownMessageError{}
8486
}
@@ -92,10 +94,61 @@ func NewMessageInfoFromCell(t cldf.ContractType, msg *cell.Cell, tlbs map[int]in
9294
return nil, fmt.Errorf("failed to decode OnRamp message for opcode 0x%X: %w", opCode, err)
9395
}
9496

95-
name := fmt.Sprintf("%s/%s", t, rt.Name())
97+
name := fmt.Sprintf("%s:%s", t, rt.Name())
9698
return NewMessageInfo(name, inst)
9799
}
98100

101+
func MustNewTLBMap(types []interface{}) map[uint64]interface{} {
102+
tlbs, err := NewTLBMap(types)
103+
if err != nil {
104+
panic(fmt.Errorf("failed to create TLB map: %w", err))
105+
}
106+
return tlbs
107+
}
108+
109+
// NewTLBMap creates a map of TL-B magic numbers to their corresponding types.
110+
// The input is a slice of TL-B struct instances.
111+
func NewTLBMap(types []interface{}) (map[uint64]interface{}, error) {
112+
tlbs := make(map[uint64]interface{})
113+
for _, typ := range types {
114+
// Use reflection to get the magic number from the type
115+
rt := reflect.TypeOf(typ)
116+
117+
magicTag := rt.Field(0).Tag.Get("tlb")
118+
magic, err := loadMagic(magicTag)
119+
if err != nil {
120+
return nil, fmt.Errorf("failed to load magic from tag %s: %w", magicTag, err)
121+
}
122+
123+
tlbs[magic] = typ
124+
}
125+
return tlbs, nil
126+
}
127+
128+
// Notice: func extracted from tonutils-go tlb package
129+
func loadMagic(tag string) (uint64, error) {
130+
var sz, base int
131+
if strings.HasPrefix(tag, "#") {
132+
base = 16
133+
sz = (len(tag) - 1) * 4
134+
} else if strings.HasPrefix(tag, "$") {
135+
base = 2
136+
sz = len(tag) - 1
137+
} else {
138+
return 0, fmt.Errorf("unknown magic value type in tag: %s", tag)
139+
}
140+
141+
if sz > 64 {
142+
return 0, fmt.Errorf("too big magic value type in tag")
143+
}
144+
145+
magic, err := strconv.ParseInt(tag[1:], base, 64)
146+
if err != nil {
147+
return 0, fmt.Errorf("corrupted magic value in tag")
148+
}
149+
return uint64(magic), nil
150+
}
151+
99152
type messageInfo struct {
100153
name string
101154
short string

0 commit comments

Comments
 (0)