From 8c927a84bcc230bedb984b72957795be9c29632d Mon Sep 17 00:00:00 2001 From: Victoria Erokhina Date: Fri, 22 Nov 2024 09:35:24 +0000 Subject: [PATCH 1/4] Save serialized traces to scylla --- pkg/api/event_handlers.go | 249 ++++++++++++++++++++++---------------- pkg/api/interfaces.go | 4 + pkg/core/trace.go | 54 +++++++++ pkg/core/transactions.go | 39 ++++++ 4 files changed, 239 insertions(+), 107 deletions(-) diff --git a/pkg/api/event_handlers.go b/pkg/api/event_handlers.go index b9753554..a3a8039c 100644 --- a/pkg/api/event_handlers.go +++ b/pkg/api/event_handlers.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "errors" "fmt" + "github.com/tonkeeper/tongo/abi" "go.uber.org/zap" "golang.org/x/exp/slices" "net/http" @@ -390,29 +391,37 @@ func (h *Handler) EmulateMessageToAccountEvent(ctx context.Context, request *oas if err != nil { return nil, toError(http.StatusBadRequest, err) } - configBase64, err := h.storage.TrimmedConfigBase64() - if err != nil { - return nil, toError(http.StatusInternalServerError, err) - } - options := []txemulator.TraceOption{ - txemulator.WithAccountsSource(h.storage), - txemulator.WithConfigBase64(configBase64), - txemulator.WithLimit(1100), - } - if !params.IgnoreSignatureCheck.Value { - options = append(options, txemulator.WithSignatureCheck()) - } - emulator, err := txemulator.NewTraceBuilder(options...) - if err != nil { - return nil, toError(http.StatusInternalServerError, err) - } - tree, err := emulator.Run(ctx, m) - if err != nil { - return nil, toProperEmulationError(err) - } - trace, err := emulatedTreeToTrace(ctx, h.executor, h.storage, tree, emulator.FinalStates(), nil, h.configPool) - if err != nil { - return nil, toError(http.StatusInternalServerError, err) + hash, err := c.HashString() + trace, _, err := h.storage.GetTraceWithState(ctx, hash) + if trace == nil { + configBase64, err := h.storage.TrimmedConfigBase64() + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + options := []txemulator.TraceOption{ + txemulator.WithAccountsSource(h.storage), + txemulator.WithConfigBase64(configBase64), + txemulator.WithLimit(1100), + } + if !params.IgnoreSignatureCheck.Value { + options = append(options, txemulator.WithSignatureCheck()) + } + emulator, err := txemulator.NewTraceBuilder(options...) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + tree, err := emulator.Run(ctx, m) + if err != nil { + return nil, toProperEmulationError(err) + } + trace, err = emulatedTreeToTrace(ctx, h.executor, h.storage, tree, emulator.FinalStates(), nil, h.configPool) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + err = h.storage.SaveTraceWithState(hash, trace, []abi.MethodInvocation{}, 24*time.Hour) + if err != nil { + fmt.Println("not saved to scylla: ", err) + } } actions, err := bath.FindActions(ctx, trace, bath.WithInformationSource(h.storage)) if err != nil { @@ -437,33 +446,41 @@ func (h *Handler) EmulateMessageToEvent(ctx context.Context, request *oas.Emulat } trace, prs := h.mempoolEmulate.traces.Get(hash) if !prs { - var m tlb.Message - if err := tlb.Unmarshal(c, &m); err != nil { - return nil, toError(http.StatusBadRequest, err) - } - configBase64, err := h.storage.TrimmedConfigBase64() - if err != nil { - return nil, toError(http.StatusInternalServerError, err) - } - options := []txemulator.TraceOption{ - txemulator.WithAccountsSource(h.storage), - txemulator.WithConfigBase64(configBase64), - } - if !params.IgnoreSignatureCheck.Value { - options = append(options, txemulator.WithSignatureCheck()) - } + hs, _ := c.HashString() + trace, _, err = h.storage.GetTraceWithState(ctx, hs) + if trace == nil { + var m tlb.Message + if err := tlb.Unmarshal(c, &m); err != nil { + return nil, toError(http.StatusBadRequest, err) + } + configBase64, err := h.storage.TrimmedConfigBase64() + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + options := []txemulator.TraceOption{ + txemulator.WithAccountsSource(h.storage), + txemulator.WithConfigBase64(configBase64), + } + if !params.IgnoreSignatureCheck.Value { + options = append(options, txemulator.WithSignatureCheck()) + } - emulator, err := txemulator.NewTraceBuilder(options...) - if err != nil { - return nil, toError(http.StatusInternalServerError, err) - } - tree, err := emulator.Run(ctx, m) - if err != nil { - return nil, toProperEmulationError(err) - } - trace, err = emulatedTreeToTrace(ctx, h.executor, h.storage, tree, emulator.FinalStates(), nil, h.configPool) - if err != nil { - return nil, toError(http.StatusInternalServerError, err) + emulator, err := txemulator.NewTraceBuilder(options...) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + tree, err := emulator.Run(ctx, m) + if err != nil { + return nil, toProperEmulationError(err) + } + trace, err = emulatedTreeToTrace(ctx, h.executor, h.storage, tree, emulator.FinalStates(), nil, h.configPool) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + err = h.storage.SaveTraceWithState(hs, trace, []abi.MethodInvocation{}, 24*time.Hour) + if err != nil { + fmt.Println("not saved to scylla: ", err) + } } } actions, err := bath.FindActions(ctx, trace, bath.WithInformationSource(h.storage)) @@ -489,34 +506,42 @@ func (h *Handler) EmulateMessageToTrace(ctx context.Context, request *oas.Emulat } trace, prs := h.mempoolEmulate.traces.Get(hash) if !prs { - var m tlb.Message - err = tlb.Unmarshal(c, &m) - if err != nil { - return nil, toError(http.StatusBadRequest, err) - } - configBase64, err := h.storage.TrimmedConfigBase64() - if err != nil { - return nil, toError(http.StatusInternalServerError, err) - } - options := []txemulator.TraceOption{ - txemulator.WithAccountsSource(h.storage), - txemulator.WithConfigBase64(configBase64), - } - if !params.IgnoreSignatureCheck.Value { - options = append(options, txemulator.WithSignatureCheck()) - } + hs, err := c.HashString() + trace, _, err = h.storage.GetTraceWithState(ctx, hs) + if trace == nil { + var m tlb.Message + err = tlb.Unmarshal(c, &m) + if err != nil { + return nil, toError(http.StatusBadRequest, err) + } + configBase64, err := h.storage.TrimmedConfigBase64() + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + options := []txemulator.TraceOption{ + txemulator.WithAccountsSource(h.storage), + txemulator.WithConfigBase64(configBase64), + } + if !params.IgnoreSignatureCheck.Value { + options = append(options, txemulator.WithSignatureCheck()) + } - emulator, err := txemulator.NewTraceBuilder(options...) - if err != nil { - return nil, toError(http.StatusInternalServerError, err) - } - tree, err := emulator.Run(ctx, m) - if err != nil { - return nil, toProperEmulationError(err) - } - trace, err = emulatedTreeToTrace(ctx, h.executor, h.storage, tree, emulator.FinalStates(), nil, h.configPool) - if err != nil { - return nil, toError(http.StatusInternalServerError, err) + emulator, err := txemulator.NewTraceBuilder(options...) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + tree, err := emulator.Run(ctx, m) + if err != nil { + return nil, toProperEmulationError(err) + } + trace, err = emulatedTreeToTrace(ctx, h.executor, h.storage, tree, emulator.FinalStates(), nil, h.configPool) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + err = h.storage.SaveTraceWithState(hs, trace, []abi.MethodInvocation{}, 24*time.Hour) + if err != nil { + fmt.Println("not saved to scylla: ", err) + } } } t := convertTrace(trace, h.addressBook) @@ -603,44 +628,54 @@ func (h *Handler) EmulateMessageToWallet(ctx context.Context, request *oas.Emula if err != nil { return nil, toError(http.StatusInternalServerError, err) } - configBase64, err := h.storage.TrimmedConfigBase64() - if err != nil { - return nil, toError(http.StatusInternalServerError, err) - } - options := []txemulator.TraceOption{ - txemulator.WithConfigBase64(configBase64), - txemulator.WithAccountsSource(h.storage), - txemulator.WithLimit(1100), - } - accounts, err := convertEmulationParameters(request.Params) - if err != nil { - return nil, toError(http.StatusBadRequest, err) - } - var states []tlb.ShardAccount - for accountID, balance := range accounts { - originalState, err := h.storage.GetAccountState(ctx, accountID) + hash, err := msgCell.HashString() + trace, _, err := h.storage.GetTraceWithState(ctx, hash) + if trace == nil { + configBase64, err := h.storage.TrimmedConfigBase64() + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + + options := []txemulator.TraceOption{ + txemulator.WithConfigBase64(configBase64), + txemulator.WithAccountsSource(h.storage), + txemulator.WithLimit(1100), + } + accounts, err := convertEmulationParameters(request.Params) + if err != nil { + return nil, toError(http.StatusBadRequest, err) + } + var states []tlb.ShardAccount + for accountID, balance := range accounts { + originalState, err := h.storage.GetAccountState(ctx, accountID) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + state, err := prepareAccountState(*walletAddress, originalState, balance) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + states = append(states, state) + } + + options = append(options, txemulator.WithAccounts(states...)) + emulator, err := txemulator.NewTraceBuilder(options...) if err != nil { return nil, toError(http.StatusInternalServerError, err) } - state, err := prepareAccountState(*walletAddress, originalState, balance) + tree, err := emulator.Run(ctx, m) + if err != nil { + return nil, toProperEmulationError(err) + } + trace, err = emulatedTreeToTrace(ctx, h.executor, h.storage, tree, emulator.FinalStates(), nil, h.configPool) if err != nil { return nil, toError(http.StatusInternalServerError, err) } - states = append(states, state) - } - options = append(options, txemulator.WithAccounts(states...)) - emulator, err := txemulator.NewTraceBuilder(options...) - if err != nil { - return nil, toError(http.StatusInternalServerError, err) - } - tree, err := emulator.Run(ctx, m) - if err != nil { - return nil, toProperEmulationError(err) - } - trace, err := emulatedTreeToTrace(ctx, h.executor, h.storage, tree, emulator.FinalStates(), nil, h.configPool) - if err != nil { - return nil, toError(http.StatusInternalServerError, err) + err = h.storage.SaveTraceWithState(hash, trace, []abi.MethodInvocation{}, 24*time.Hour) + if err != nil { + fmt.Println("not saved to scylla: ", err) + } } t := convertTrace(trace, h.addressBook) actions, err := bath.FindActions(ctx, trace, bath.ForAccount(*walletAddress), bath.WithInformationSource(h.storage)) diff --git a/pkg/api/interfaces.go b/pkg/api/interfaces.go index 85e6d8ef..bbd7e627 100644 --- a/pkg/api/interfaces.go +++ b/pkg/api/interfaces.go @@ -3,6 +3,7 @@ package api import ( "context" "crypto/ed25519" + "time" "github.com/tonkeeper/opentonapi/pkg/gasless" "github.com/tonkeeper/opentonapi/pkg/oas" @@ -111,6 +112,9 @@ type storage interface { GetAccountMultisigs(ctx context.Context, accountID ton.AccountID) ([]core.Multisig, error) GetMultisigByID(ctx context.Context, accountID ton.AccountID) (*core.Multisig, error) + SaveTraceWithState(msgHash string, trace *core.Trace, getMethods []abi.MethodInvocation, ttl time.Duration) error + GetTraceWithState(ctx context.Context, msgHash string) (*core.Trace, []abi.MethodInvocation, error) + liteStorageRaw } diff --git a/pkg/core/trace.go b/pkg/core/trace.go index 1f26effa..f96713e7 100644 --- a/pkg/core/trace.go +++ b/pkg/core/trace.go @@ -2,7 +2,9 @@ package core import ( "context" + "encoding/json" "errors" + "github.com/tonkeeper/tongo/ton" "sync" "github.com/shopspring/decimal" @@ -65,6 +67,58 @@ func (t *Trace) SetAdditionalInfo(info *TraceAdditionalInfo) { t.additionalInfo = info } +func (t *TraceAdditionalInfo) MarshalJSON() ([]byte, error) { + type Alias struct { + JettonMasters map[string]string `json:",omitempty"` + NftSaleContract *NftSaleContract `json:",omitempty"` + STONfiPool *STONfiPool `json:",omitempty"` + EmulatedTeleitemNFT *EmulatedTeleitemNFT `json:",omitempty"` + } + + masters := make(map[string]string) + if t.JettonMasters != nil { + for k, v := range t.JettonMasters { + masters[k.String()] = v.String() + } + } + + return json.Marshal(&Alias{ + JettonMasters: masters, + NftSaleContract: t.NftSaleContract, + STONfiPool: t.STONfiPool, + EmulatedTeleitemNFT: t.EmulatedTeleitemNFT, + }) +} + +func (t *TraceAdditionalInfo) UnmarshalJSON(data []byte) error { + type Alias struct { + JettonMasters map[string]string `json:",omitempty"` + NftSaleContract *NftSaleContract `json:",omitempty"` + STONfiPool *STONfiPool `json:",omitempty"` + EmulatedTeleitemNFT *EmulatedTeleitemNFT `json:",omitempty"` + } + + aux := &Alias{} + if err := json.Unmarshal(data, aux); err != nil { + return err + } + + if aux.JettonMasters != nil { + t.JettonMasters = make(map[tongo.AccountID]tongo.AccountID) + for kStr, vStr := range aux.JettonMasters { + key := ton.MustParseAccountID(kStr) + val := ton.MustParseAccountID(vStr) + t.JettonMasters[key] = val + } + } + + t.NftSaleContract = aux.NftSaleContract + t.STONfiPool = aux.STONfiPool + t.EmulatedTeleitemNFT = aux.EmulatedTeleitemNFT + + return nil +} + func (t *Trace) InProgress() bool { return t.countUncompleted() != 0 } diff --git a/pkg/core/transactions.go b/pkg/core/transactions.go index b6b6db24..22c8e88f 100644 --- a/pkg/core/transactions.go +++ b/pkg/core/transactions.go @@ -1,9 +1,11 @@ package core import ( + "encoding/json" "fmt" "github.com/tonkeeper/tongo/ton" "math/big" + "reflect" "strings" "github.com/tonkeeper/tongo/abi" @@ -176,6 +178,43 @@ type Message struct { DecodedBody *DecodedMessageBody } +func (m *Message) UnmarshalJSON(data []byte) error { + type Alias Message + r := struct { + *Alias + DecodedBody struct { + Operation string + Value json.RawMessage + } + }{ + Alias: (*Alias)(m), + } + if err := json.Unmarshal(data, &r); err != nil { + return err + } + var msgTypes map[string]any + switch r.MsgType { + case IntMsg: + msgTypes = abi.KnownMsgInTypes + case ExtOutMsg: + msgTypes = abi.KnownMsgExtOutTypes + case ExtInMsg: + msgTypes = abi.KnownMsgExtInTypes + } + if v, present := msgTypes[r.DecodedBody.Operation]; present { + p := reflect.New(reflect.TypeOf(v)) + if err := json.Unmarshal(r.DecodedBody.Value, p.Interface()); err != nil { + return err + } + m.DecodedBody = &DecodedMessageBody{ + Operation: r.DecodedBody.Operation, + Value: p.Elem().Interface(), + } + return nil + } + return nil +} + // DecodedMessageBody contains a message body decoded by tongo.abi package. type DecodedMessageBody struct { Operation string From f218d63610ef0b84a22c16ff806dff244cd3e445 Mon Sep 17 00:00:00 2001 From: Victoria Erokhina Date: Fri, 22 Nov 2024 09:37:57 +0000 Subject: [PATCH 2/4] rewrite error msg --- pkg/api/event_handlers.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/api/event_handlers.go b/pkg/api/event_handlers.go index a3a8039c..d0362905 100644 --- a/pkg/api/event_handlers.go +++ b/pkg/api/event_handlers.go @@ -420,7 +420,7 @@ func (h *Handler) EmulateMessageToAccountEvent(ctx context.Context, request *oas } err = h.storage.SaveTraceWithState(hash, trace, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { - fmt.Println("not saved to scylla: ", err) + fmt.Println("trace not saved: ", err) } } actions, err := bath.FindActions(ctx, trace, bath.WithInformationSource(h.storage)) @@ -479,7 +479,7 @@ func (h *Handler) EmulateMessageToEvent(ctx context.Context, request *oas.Emulat } err = h.storage.SaveTraceWithState(hs, trace, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { - fmt.Println("not saved to scylla: ", err) + fmt.Println("trace not saved: ", err) } } } @@ -540,7 +540,7 @@ func (h *Handler) EmulateMessageToTrace(ctx context.Context, request *oas.Emulat } err = h.storage.SaveTraceWithState(hs, trace, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { - fmt.Println("not saved to scylla: ", err) + fmt.Println("trace not saved: ", err) } } } @@ -674,7 +674,7 @@ func (h *Handler) EmulateMessageToWallet(ctx context.Context, request *oas.Emula } err = h.storage.SaveTraceWithState(hash, trace, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { - fmt.Println("not saved to scylla: ", err) + fmt.Println("trace not saved: ", err) } } t := convertTrace(trace, h.addressBook) From 220f35ed1569de220d7925534490133d4ff2401b Mon Sep 17 00:00:00 2001 From: Victoria Erokhina Date: Mon, 2 Dec 2024 14:50:58 +0000 Subject: [PATCH 3/4] fix comments --- pkg/api/event_handlers.go | 34 +++++++++++++++++++++++++++++----- pkg/api/interfaces.go | 2 +- pkg/litestorage/litestorage.go | 8 ++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/pkg/api/event_handlers.go b/pkg/api/event_handlers.go index d0362905..3f315ee1 100644 --- a/pkg/api/event_handlers.go +++ b/pkg/api/event_handlers.go @@ -392,7 +392,13 @@ func (h *Handler) EmulateMessageToAccountEvent(ctx context.Context, request *oas return nil, toError(http.StatusBadRequest, err) } hash, err := c.HashString() + if err != nil { + return nil, toError(http.StatusBadRequest, err) + } trace, _, err := h.storage.GetTraceWithState(ctx, hash) + if err != nil { + h.logger.Warn("get trace from storage: ", zap.Error(err)) + } if trace == nil { configBase64, err := h.storage.TrimmedConfigBase64() if err != nil { @@ -418,7 +424,7 @@ func (h *Handler) EmulateMessageToAccountEvent(ctx context.Context, request *oas if err != nil { return nil, toError(http.StatusInternalServerError, err) } - err = h.storage.SaveTraceWithState(hash, trace, []abi.MethodInvocation{}, 24*time.Hour) + err = h.storage.SaveTraceWithState(ctx, hash, trace, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { fmt.Println("trace not saved: ", err) } @@ -446,8 +452,14 @@ func (h *Handler) EmulateMessageToEvent(ctx context.Context, request *oas.Emulat } trace, prs := h.mempoolEmulate.traces.Get(hash) if !prs { - hs, _ := c.HashString() + hs, err := c.HashString() + if err != nil { + return nil, toError(http.StatusBadRequest, err) + } trace, _, err = h.storage.GetTraceWithState(ctx, hs) + if err != nil { + h.logger.Warn("get trace from storage: ", zap.Error(err)) + } if trace == nil { var m tlb.Message if err := tlb.Unmarshal(c, &m); err != nil { @@ -477,7 +489,7 @@ func (h *Handler) EmulateMessageToEvent(ctx context.Context, request *oas.Emulat if err != nil { return nil, toError(http.StatusInternalServerError, err) } - err = h.storage.SaveTraceWithState(hs, trace, []abi.MethodInvocation{}, 24*time.Hour) + err = h.storage.SaveTraceWithState(ctx, hs, trace, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { fmt.Println("trace not saved: ", err) } @@ -507,7 +519,13 @@ func (h *Handler) EmulateMessageToTrace(ctx context.Context, request *oas.Emulat trace, prs := h.mempoolEmulate.traces.Get(hash) if !prs { hs, err := c.HashString() + if err != nil { + return nil, toError(http.StatusBadRequest, err) + } trace, _, err = h.storage.GetTraceWithState(ctx, hs) + if err != nil { + h.logger.Warn("get trace from storage: ", zap.Error(err)) + } if trace == nil { var m tlb.Message err = tlb.Unmarshal(c, &m) @@ -538,7 +556,7 @@ func (h *Handler) EmulateMessageToTrace(ctx context.Context, request *oas.Emulat if err != nil { return nil, toError(http.StatusInternalServerError, err) } - err = h.storage.SaveTraceWithState(hs, trace, []abi.MethodInvocation{}, 24*time.Hour) + err = h.storage.SaveTraceWithState(ctx, hs, trace, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { fmt.Println("trace not saved: ", err) } @@ -630,7 +648,13 @@ func (h *Handler) EmulateMessageToWallet(ctx context.Context, request *oas.Emula } hash, err := msgCell.HashString() + if err != nil { + return nil, toError(http.StatusBadRequest, err) + } trace, _, err := h.storage.GetTraceWithState(ctx, hash) + if err != nil { + h.logger.Warn("get trace from storage: ", zap.Error(err)) + } if trace == nil { configBase64, err := h.storage.TrimmedConfigBase64() if err != nil { @@ -672,7 +696,7 @@ func (h *Handler) EmulateMessageToWallet(ctx context.Context, request *oas.Emula if err != nil { return nil, toError(http.StatusInternalServerError, err) } - err = h.storage.SaveTraceWithState(hash, trace, []abi.MethodInvocation{}, 24*time.Hour) + err = h.storage.SaveTraceWithState(ctx, hash, trace, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { fmt.Println("trace not saved: ", err) } diff --git a/pkg/api/interfaces.go b/pkg/api/interfaces.go index bbd7e627..6c33b96e 100644 --- a/pkg/api/interfaces.go +++ b/pkg/api/interfaces.go @@ -112,7 +112,7 @@ type storage interface { GetAccountMultisigs(ctx context.Context, accountID ton.AccountID) ([]core.Multisig, error) GetMultisigByID(ctx context.Context, accountID ton.AccountID) (*core.Multisig, error) - SaveTraceWithState(msgHash string, trace *core.Trace, getMethods []abi.MethodInvocation, ttl time.Duration) error + SaveTraceWithState(ctx context.Context, msgHash string, trace *core.Trace, getMethods []abi.MethodInvocation, ttl time.Duration) error GetTraceWithState(ctx context.Context, msgHash string) (*core.Trace, []abi.MethodInvocation, error) liteStorageRaw diff --git a/pkg/litestorage/litestorage.go b/pkg/litestorage/litestorage.go index b914d60a..eacd62c8 100644 --- a/pkg/litestorage/litestorage.go +++ b/pkg/litestorage/litestorage.go @@ -566,3 +566,11 @@ func (s *LiteStorage) GetAccountMultisigs(ctx context.Context, accountID ton.Acc func (s *LiteStorage) GetMultisigByID(ctx context.Context, accountID ton.AccountID) (*core.Multisig, error) { return nil, fmt.Errorf("not implemented") } + +func (s *LiteStorage) SaveTraceWithState(ctx context.Context, msgHash string, trace *core.Trace, getMethods []abi.MethodInvocation, ttl time.Duration) error { + return fmt.Errorf("not implemented") +} + +func (s *LiteStorage) GetTraceWithState(ctx context.Context, msgHash string) (*core.Trace, []abi.MethodInvocation, error) { + return nil, nil, fmt.Errorf("not implemented") +} From b498216d03e406703812d66045d5b27373364477 Mon Sep 17 00:00:00 2001 From: Victoria Erokhina Date: Mon, 10 Mar 2025 17:36:29 +0000 Subject: [PATCH 4/4] save tongo version --- pkg/api/event_handlers.go | 24 ++++++++++++------------ pkg/api/handler.go | 7 +++++++ pkg/api/interfaces.go | 4 ++-- pkg/api/utils.go | 31 +++++++++++++++++++++++++++++++ pkg/litestorage/litestorage.go | 6 +++--- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/pkg/api/event_handlers.go b/pkg/api/event_handlers.go index 3f315ee1..43cacfe2 100644 --- a/pkg/api/event_handlers.go +++ b/pkg/api/event_handlers.go @@ -395,11 +395,11 @@ func (h *Handler) EmulateMessageToAccountEvent(ctx context.Context, request *oas if err != nil { return nil, toError(http.StatusBadRequest, err) } - trace, _, err := h.storage.GetTraceWithState(ctx, hash) + trace, version, _, err := h.storage.GetTraceWithState(ctx, hash) if err != nil { h.logger.Warn("get trace from storage: ", zap.Error(err)) } - if trace == nil { + if trace == nil || h.tongoVersion == 0 || version > h.tongoVersion { configBase64, err := h.storage.TrimmedConfigBase64() if err != nil { return nil, toError(http.StatusInternalServerError, err) @@ -424,7 +424,7 @@ func (h *Handler) EmulateMessageToAccountEvent(ctx context.Context, request *oas if err != nil { return nil, toError(http.StatusInternalServerError, err) } - err = h.storage.SaveTraceWithState(ctx, hash, trace, []abi.MethodInvocation{}, 24*time.Hour) + err = h.storage.SaveTraceWithState(ctx, hash, trace, h.tongoVersion, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { fmt.Println("trace not saved: ", err) } @@ -456,11 +456,11 @@ func (h *Handler) EmulateMessageToEvent(ctx context.Context, request *oas.Emulat if err != nil { return nil, toError(http.StatusBadRequest, err) } - trace, _, err = h.storage.GetTraceWithState(ctx, hs) + trace, version, _, err := h.storage.GetTraceWithState(ctx, hs) if err != nil { h.logger.Warn("get trace from storage: ", zap.Error(err)) } - if trace == nil { + if trace == nil || h.tongoVersion == 0 || version > h.tongoVersion { var m tlb.Message if err := tlb.Unmarshal(c, &m); err != nil { return nil, toError(http.StatusBadRequest, err) @@ -489,7 +489,7 @@ func (h *Handler) EmulateMessageToEvent(ctx context.Context, request *oas.Emulat if err != nil { return nil, toError(http.StatusInternalServerError, err) } - err = h.storage.SaveTraceWithState(ctx, hs, trace, []abi.MethodInvocation{}, 24*time.Hour) + err = h.storage.SaveTraceWithState(ctx, hs, trace, h.tongoVersion, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { fmt.Println("trace not saved: ", err) } @@ -522,11 +522,11 @@ func (h *Handler) EmulateMessageToTrace(ctx context.Context, request *oas.Emulat if err != nil { return nil, toError(http.StatusBadRequest, err) } - trace, _, err = h.storage.GetTraceWithState(ctx, hs) + trace, version, _, err := h.storage.GetTraceWithState(ctx, hs) if err != nil { h.logger.Warn("get trace from storage: ", zap.Error(err)) } - if trace == nil { + if trace == nil || h.tongoVersion == 0 || version > h.tongoVersion { var m tlb.Message err = tlb.Unmarshal(c, &m) if err != nil { @@ -556,7 +556,7 @@ func (h *Handler) EmulateMessageToTrace(ctx context.Context, request *oas.Emulat if err != nil { return nil, toError(http.StatusInternalServerError, err) } - err = h.storage.SaveTraceWithState(ctx, hs, trace, []abi.MethodInvocation{}, 24*time.Hour) + err = h.storage.SaveTraceWithState(ctx, hs, trace, h.tongoVersion, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { fmt.Println("trace not saved: ", err) } @@ -651,11 +651,11 @@ func (h *Handler) EmulateMessageToWallet(ctx context.Context, request *oas.Emula if err != nil { return nil, toError(http.StatusBadRequest, err) } - trace, _, err := h.storage.GetTraceWithState(ctx, hash) + trace, version, _, err := h.storage.GetTraceWithState(ctx, hash) if err != nil { h.logger.Warn("get trace from storage: ", zap.Error(err)) } - if trace == nil { + if trace == nil || h.tongoVersion == 0 || version > h.tongoVersion { configBase64, err := h.storage.TrimmedConfigBase64() if err != nil { return nil, toError(http.StatusInternalServerError, err) @@ -696,7 +696,7 @@ func (h *Handler) EmulateMessageToWallet(ctx context.Context, request *oas.Emula if err != nil { return nil, toError(http.StatusInternalServerError, err) } - err = h.storage.SaveTraceWithState(ctx, hash, trace, []abi.MethodInvocation{}, 24*time.Hour) + err = h.storage.SaveTraceWithState(ctx, hash, trace, h.tongoVersion, []abi.MethodInvocation{}, 24*time.Hour) if err != nil { fmt.Println("trace not saved: ", err) } diff --git a/pkg/api/handler.go b/pkg/api/handler.go index 9f2fc0c1..96a7988c 100644 --- a/pkg/api/handler.go +++ b/pkg/api/handler.go @@ -3,6 +3,7 @@ package api import ( "context" "fmt" + "golang.org/x/exp/slog" "sync" "github.com/go-faster/errors" @@ -51,6 +52,7 @@ type Handler struct { mempoolEmulate mempoolEmulate // ctxToDetails converts a request context to a details instance. ctxToDetails ctxToDetails + tongoVersion int // mempoolEmulateIgnoreAccounts, we don't track pending transactions for this list of accounts. mempoolEmulateIgnoreAccounts map[tongo.AccountID]struct{} @@ -218,6 +220,10 @@ func NewHandler(logger *zap.Logger, opts ...Option) (*Handler, error) { if options.score == nil { options.score = score.NewScore() } + tongoVersion, err := GetPackageVersionInt("tongo") + if err != nil { + slog.Warn("unable to detect tongo version", "err", err) + } return &Handler{ logger: logger, storage: options.storage, @@ -244,6 +250,7 @@ func NewHandler(logger *zap.Logger, opts ...Option) (*Handler, error) { mempoolEmulateIgnoreAccounts: map[tongo.AccountID]struct{}{ tongo.MustParseAddress("0:0000000000000000000000000000000000000000000000000000000000000000").ID: {}, }, + tongoVersion: tongoVersion, blacklistedBocCache: cache.NewLRUCache[[32]byte, struct{}](100000, "blacklisted_boc_cache"), getMethodsCache: cache.NewLRUCache[string, *oas.MethodExecutionResult](100000, "get_methods_cache"), tonConnect: tonConnect, diff --git a/pkg/api/interfaces.go b/pkg/api/interfaces.go index 6c33b96e..f702f64a 100644 --- a/pkg/api/interfaces.go +++ b/pkg/api/interfaces.go @@ -112,8 +112,8 @@ type storage interface { GetAccountMultisigs(ctx context.Context, accountID ton.AccountID) ([]core.Multisig, error) GetMultisigByID(ctx context.Context, accountID ton.AccountID) (*core.Multisig, error) - SaveTraceWithState(ctx context.Context, msgHash string, trace *core.Trace, getMethods []abi.MethodInvocation, ttl time.Duration) error - GetTraceWithState(ctx context.Context, msgHash string) (*core.Trace, []abi.MethodInvocation, error) + SaveTraceWithState(ctx context.Context, msgHash string, trace *core.Trace, version int, getMethods []abi.MethodInvocation, ttl time.Duration) error + GetTraceWithState(ctx context.Context, msgHash string) (*core.Trace, int, []abi.MethodInvocation, error) liteStorageRaw } diff --git a/pkg/api/utils.go b/pkg/api/utils.go index 3249b98b..bc15233b 100644 --- a/pkg/api/utils.go +++ b/pkg/api/utils.go @@ -2,6 +2,9 @@ package api import ( "fmt" + "runtime/debug" + "strconv" + "strings" "github.com/tonkeeper/tongo/boc" ) @@ -25,3 +28,31 @@ func deserializeSingleBoc(bocStr string) (*boc.Cell, error) { } return cells[0], nil } + +func GetPackageVersionInt(packagePath string) (int, error) { + info, ok := debug.ReadBuildInfo() + if !ok { + return 0, fmt.Errorf("error getting build info") + } + + for _, dep := range info.Deps { + if strings.Contains(dep.Path, packagePath) { + version := strings.TrimPrefix(dep.Version, "v") + + parts := strings.Split(version, ".") + + result := 0 + for _, part := range parts { + num, err := strconv.Atoi(part) + if err != nil { + return 0, fmt.Errorf("error parsing version number: %v", err) + } + result = result*100 + num + } + + return result, nil + } + } + + return 0, fmt.Errorf("package %s not found", packagePath) +} diff --git a/pkg/litestorage/litestorage.go b/pkg/litestorage/litestorage.go index eacd62c8..3149fa0e 100644 --- a/pkg/litestorage/litestorage.go +++ b/pkg/litestorage/litestorage.go @@ -567,10 +567,10 @@ func (s *LiteStorage) GetMultisigByID(ctx context.Context, accountID ton.Account return nil, fmt.Errorf("not implemented") } -func (s *LiteStorage) SaveTraceWithState(ctx context.Context, msgHash string, trace *core.Trace, getMethods []abi.MethodInvocation, ttl time.Duration) error { +func (s *LiteStorage) SaveTraceWithState(ctx context.Context, msgHash string, trace *core.Trace, version int, getMethods []abi.MethodInvocation, ttl time.Duration) error { return fmt.Errorf("not implemented") } -func (s *LiteStorage) GetTraceWithState(ctx context.Context, msgHash string) (*core.Trace, []abi.MethodInvocation, error) { - return nil, nil, fmt.Errorf("not implemented") +func (s *LiteStorage) GetTraceWithState(ctx context.Context, msgHash string) (*core.Trace, int, []abi.MethodInvocation, error) { + return nil, 0, nil, fmt.Errorf("not implemented") }