From 7f6f90fb15b5f63774928b92baa69c63d7558bd5 Mon Sep 17 00:00:00 2001 From: Zakhar Petukhov Date: Fri, 13 Dec 2024 15:33:20 +0800 Subject: [PATCH] update the account inspection method to get the source --- api/openapi.json | 88 +++++- api/openapi.yml | 101 ++++-- pkg/api/account_handlers.go | 22 +- pkg/api/handler.go | 45 ++- pkg/api/interfaces.go | 5 + pkg/oas/oas_json_gen.go | 564 ++++++++++++++++++++++++---------- pkg/oas/oas_schemas_gen.go | 212 ++++++++----- pkg/oas/oas_validators_gen.go | 49 ++- pkg/verifier/verifier.go | 38 +++ 9 files changed, 814 insertions(+), 310 deletions(-) create mode 100644 pkg/verifier/verifier.go diff --git a/api/openapi.json b/api/openapi.json index f4a1fdd3..6132e318 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -1531,35 +1531,28 @@ }, "compiler": { "enum": [ - "func" + "func", + "fift", + "tact" ], "type": "string" }, "methods": { "items": { - "properties": { - "id": { - "format": "int64", - "type": "integer" - }, - "method": { - "example": "get_something", - "type": "string" - } - }, - "required": [ - "id", - "method" - ], - "type": "object" + "$ref": "#/components/schemas/Method" }, "type": "array" + }, + "source": { + "$ref": "#/components/schemas/Source" } }, "required": [ "code", "code_hash", - "methods" + "methods", + "compiler", + "source" ], "type": "object" }, @@ -4318,6 +4311,23 @@ ], "type": "object" }, + "Method": { + "properties": { + "id": { + "format": "int64", + "type": "integer" + }, + "method": { + "example": "get_something", + "type": "string" + } + }, + "required": [ + "id", + "method" + ], + "type": "object" + }, "MethodExecutionResult": { "properties": { "decoded": {}, @@ -5364,6 +5374,50 @@ ], "type": "object" }, + "Source": { + "properties": { + "files": { + "items": { + "$ref": "#/components/schemas/SourceFile" + }, + "type": "array" + } + }, + "required": [ + "files" + ], + "type": "object" + }, + "SourceFile": { + "properties": { + "content": { + "type": "string" + }, + "include_in_command": { + "example": false, + "type": "boolean" + }, + "is_entrypoint": { + "example": false, + "type": "boolean" + }, + "is_std_lib": { + "example": false, + "type": "boolean" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "content", + "is_entrypoint", + "is_std_lib", + "include_in_command" + ], + "type": "object" + }, "StateInit": { "properties": { "boc": { diff --git a/api/openapi.yml b/api/openapi.yml index 81e3c953..1fccebc5 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -7398,6 +7398,8 @@ components: - code - code_hash - methods + - compiler + - source properties: code: type: string @@ -7407,21 +7409,15 @@ components: methods: type: array items: - type: object - required: - - id - - method - properties: - id: - type: integer - format: int64 - method: - type: string - example: "get_something" + $ref: '#/components/schemas/Method' compiler: type: string enum: - func + - fift + - tact + source: + $ref: '#/components/schemas/Source' PoolImplementationType: type: string enum: @@ -7473,26 +7469,69 @@ components: format: int64 example: 1668436763 ExtraCurrency: - type: object - required: - - id - - amount - - decimals - properties: - id: - type: integer - example: 239 - format: int32 - amount: - type: string - x-js-format: bigint - example: "1000000000" - name: - type: string - example: FMS - decimals: - type: integer - example: 5 + type: object + required: + - id + - amount + - decimals + properties: + id: + type: integer + example: 239 + format: int32 + amount: + type: string + x-js-format: bigint + example: "1000000000" + name: + type: string + example: FMS + decimals: + type: integer + example: 5 + SourceFile: + type: object + required: + - name + - content + - is_entrypoint + - is_std_lib + - include_in_command + properties: + name: + type: string + content: + type: string + is_entrypoint: + type: boolean + example: false + is_std_lib: + type: boolean + example: false + include_in_command: + type: boolean + example: false + Source: + type: object + required: + - files + properties: + files: + type: array + items: + $ref: '#/components/schemas/SourceFile' + Method: + type: object + required: + - id + - method + properties: + id: + type: integer + format: int64 + method: + type: string + example: "get_something" responses: Error: diff --git a/pkg/api/account_handlers.go b/pkg/api/account_handlers.go index bce4ac8d..1ba3568e 100644 --- a/pkg/api/account_handlers.go +++ b/pkg/api/account_handlers.go @@ -8,12 +8,13 @@ import ( "encoding/json" "errors" "fmt" - "golang.org/x/exp/slices" "net/http" "sort" "strings" "time" + "golang.org/x/exp/slices" + "github.com/cespare/xxhash/v2" "github.com/go-faster/jx" "github.com/tonkeeper/opentonapi/internal/g" @@ -487,14 +488,29 @@ func (h *Handler) BlockchainAccountInspect(ctx context.Context, params oas.Block if err != nil { return nil, toError(http.StatusInternalServerError, err) } + source, err := h.verifierSource.GetAccountSource(account.ID) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + sourceFiles := make([]oas.SourceFile, len(source.Files)) + for idx, file := range source.Files { + sourceFiles[idx] = oas.SourceFile{ + Name: file.Name, + Content: file.Content, + IsEntrypoint: file.IsEntrypoint, + IsStdLib: file.IsStdLib, + IncludeInCommand: file.IncludeInCommand, + } + } resp := oas.BlockchainAccountInspect{ Code: hex.EncodeToString(rawAccount.Code), CodeHash: hex.EncodeToString(codeHash), - Compiler: oas.NewOptBlockchainAccountInspectCompiler(oas.BlockchainAccountInspectCompilerFunc), + Compiler: oas.BlockchainAccountInspectCompiler(source.Compiler), + Source: oas.Source{Files: sourceFiles}, } for _, methodID := range methods { if method, ok := code.Methods[methodID]; ok { - resp.Methods = append(resp.Methods, oas.BlockchainAccountInspectMethodsItem{ + resp.Methods = append(resp.Methods, oas.Method{ ID: methodID, Method: string(method), }) diff --git a/pkg/api/handler.go b/pkg/api/handler.go index 382d3f79..80b01b36 100644 --- a/pkg/api/handler.go +++ b/pkg/api/handler.go @@ -9,6 +9,7 @@ import ( "github.com/tonkeeper/opentonapi/pkg/chainstate" "github.com/tonkeeper/opentonapi/pkg/core" "github.com/tonkeeper/opentonapi/pkg/rates" + "github.com/tonkeeper/opentonapi/pkg/verifier" "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/contract/dns" "github.com/tonkeeper/tongo/tep64" @@ -37,11 +38,12 @@ type Handler struct { executor executor gasless Gasless - limits Limits - spamFilter SpamFilter - ratesSource ratesSource - metaCache metadataCache - tonConnect *tonconnect.Server + limits Limits + spamFilter SpamFilter + ratesSource ratesSource + metaCache metadataCache + tonConnect *tonconnect.Server + verifierSource verifierSource // mempoolEmulate contains results of emulation of messages that are in the mempool. mempoolEmulate mempoolEmulate @@ -80,6 +82,7 @@ type Options struct { tonConnectSecret string ctxToDetails ctxToDetails gasless Gasless + verifier verifierSource } type Option func(o *Options) @@ -149,6 +152,12 @@ func WithGasless(gasless Gasless) Option { } } +func WithVerifier(verifier verifierSource) Option { + return func(o *Options) { + o.verifier = verifier + } +} + func NewHandler(logger *zap.Logger, opts ...Option) (*Handler, error) { options := &Options{} for _, o := range opts { @@ -181,6 +190,9 @@ func NewHandler(logger *zap.Logger, opts ...Option) (*Handler, error) { if err != nil { return nil, err } + if options.verifier == nil { + options.verifier = verifier.NewVerifier() + } configPool := &sync.Pool{ New: func() interface{} { config, err := tvm.CreateConfig(configBase64) @@ -195,17 +207,18 @@ func NewHandler(logger *zap.Logger, opts ...Option) (*Handler, error) { return nil, fmt.Errorf("failed to init tonconnect") } return &Handler{ - logger: logger, - storage: options.storage, - state: options.chainState, - addressBook: options.addressBook, - msgSender: options.msgSender, - executor: options.executor, - limits: options.limits, - spamFilter: options.spamFilter, - ctxToDetails: options.ctxToDetails, - gasless: options.gasless, - ratesSource: rates.InitCalculator(options.ratesSource), + logger: logger, + storage: options.storage, + state: options.chainState, + addressBook: options.addressBook, + msgSender: options.msgSender, + executor: options.executor, + limits: options.limits, + spamFilter: options.spamFilter, + ctxToDetails: options.ctxToDetails, + gasless: options.gasless, + verifierSource: options.verifier, + ratesSource: rates.InitCalculator(options.ratesSource), metaCache: metadataCache{ collectionsCache: cache.NewLRUCache[tongo.AccountID, tep64.Metadata](10000, "nft_metadata_cache"), jettonsCache: cache.NewLRUCache[tongo.AccountID, tep64.Metadata](10000, "jetton_metadata_cache"), diff --git a/pkg/api/interfaces.go b/pkg/api/interfaces.go index e045da95..40715245 100644 --- a/pkg/api/interfaces.go +++ b/pkg/api/interfaces.go @@ -6,6 +6,7 @@ import ( "github.com/tonkeeper/opentonapi/pkg/gasless" "github.com/tonkeeper/opentonapi/pkg/oas" + "github.com/tonkeeper/opentonapi/pkg/verifier" "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/abi" "github.com/tonkeeper/tongo/boc" @@ -184,6 +185,10 @@ type SpamFilter interface { NftTrust(address tongo.AccountID, collection *ton.AccountID, description, image string) core.TrustType } +type verifierSource interface { + GetAccountSource(accountID ton.AccountID) (verifier.Source, error) +} + type metadataCache struct { collectionsCache cache.Cache[tongo.AccountID, tep64.Metadata] jettonsCache cache.Cache[tongo.AccountID, tep64.Metadata] diff --git a/pkg/oas/oas_json_gen.go b/pkg/oas/oas_json_gen.go index 53b083d5..4d6b3b3a 100644 --- a/pkg/oas/oas_json_gen.go +++ b/pkg/oas/oas_json_gen.go @@ -4591,18 +4591,21 @@ func (s *BlockchainAccountInspect) encodeFields(e *jx.Encoder) { e.ArrEnd() } { - if s.Compiler.Set { - e.FieldStart("compiler") - s.Compiler.Encode(e) - } + e.FieldStart("compiler") + s.Compiler.Encode(e) + } + { + e.FieldStart("source") + s.Source.Encode(e) } } -var jsonFieldsNameOfBlockchainAccountInspect = [4]string{ +var jsonFieldsNameOfBlockchainAccountInspect = [5]string{ 0: "code", 1: "code_hash", 2: "methods", 3: "compiler", + 4: "source", } // Decode decodes BlockchainAccountInspect from json. @@ -4641,9 +4644,9 @@ func (s *BlockchainAccountInspect) Decode(d *jx.Decoder) error { case "methods": requiredBitSet[0] |= 1 << 2 if err := func() error { - s.Methods = make([]BlockchainAccountInspectMethodsItem, 0) + s.Methods = make([]Method, 0) if err := d.Arr(func(d *jx.Decoder) error { - var elem BlockchainAccountInspectMethodsItem + var elem Method if err := elem.Decode(d); err != nil { return err } @@ -4657,8 +4660,8 @@ func (s *BlockchainAccountInspect) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"methods\"") } case "compiler": + requiredBitSet[0] |= 1 << 3 if err := func() error { - s.Compiler.Reset() if err := s.Compiler.Decode(d); err != nil { return err } @@ -4666,6 +4669,16 @@ func (s *BlockchainAccountInspect) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"compiler\"") } + case "source": + requiredBitSet[0] |= 1 << 4 + if err := func() error { + if err := s.Source.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"source\"") + } default: return d.Skip() } @@ -4676,7 +4689,7 @@ func (s *BlockchainAccountInspect) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00000111, + 0b00011111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -4740,6 +4753,10 @@ func (s *BlockchainAccountInspectCompiler) Decode(d *jx.Decoder) error { switch BlockchainAccountInspectCompiler(v) { case BlockchainAccountInspectCompilerFunc: *s = BlockchainAccountInspectCompilerFunc + case BlockchainAccountInspectCompilerFift: + *s = BlockchainAccountInspectCompilerFift + case BlockchainAccountInspectCompilerTact: + *s = BlockchainAccountInspectCompilerTact default: *s = BlockchainAccountInspectCompiler(v) } @@ -4760,119 +4777,6 @@ func (s *BlockchainAccountInspectCompiler) UnmarshalJSON(data []byte) error { return s.Decode(d) } -// Encode implements json.Marshaler. -func (s *BlockchainAccountInspectMethodsItem) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *BlockchainAccountInspectMethodsItem) encodeFields(e *jx.Encoder) { - { - e.FieldStart("id") - e.Int64(s.ID) - } - { - e.FieldStart("method") - e.Str(s.Method) - } -} - -var jsonFieldsNameOfBlockchainAccountInspectMethodsItem = [2]string{ - 0: "id", - 1: "method", -} - -// Decode decodes BlockchainAccountInspectMethodsItem from json. -func (s *BlockchainAccountInspectMethodsItem) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode BlockchainAccountInspectMethodsItem to nil") - } - var requiredBitSet [1]uint8 - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "id": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Int64() - s.ID = int64(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"id\"") - } - case "method": - requiredBitSet[0] |= 1 << 1 - if err := func() error { - v, err := d.Str() - s.Method = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"method\"") - } - default: - return d.Skip() - } - return nil - }); err != nil { - return errors.Wrap(err, "decode BlockchainAccountInspectMethodsItem") - } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00000011, - } { - if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { - // Mask only required fields and check equality to mask using XOR. - // - // If XOR result is not zero, result is not equal to expected, so some fields are missed. - // Bits of fields which would be set are actually bits of missed fields. - missed := bits.OnesCount8(result) - for bitN := 0; bitN < missed; bitN++ { - bitIdx := bits.TrailingZeros8(result) - fieldIdx := i*8 + bitIdx - var name string - if fieldIdx < len(jsonFieldsNameOfBlockchainAccountInspectMethodsItem) { - name = jsonFieldsNameOfBlockchainAccountInspectMethodsItem[fieldIdx] - } else { - name = strconv.Itoa(fieldIdx) - } - failures = append(failures, validate.FieldError{ - Name: name, - Error: validate.ErrFieldRequired, - }) - // Reset bit. - result &^= 1 << bitIdx - } - } - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s *BlockchainAccountInspectMethodsItem) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *BlockchainAccountInspectMethodsItem) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - // Encode implements json.Marshaler. func (s *BlockchainBlock) Encode(e *jx.Encoder) { e.ObjStart() @@ -26623,6 +26527,119 @@ func (s *MessageMsgType) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s *Method) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Method) encodeFields(e *jx.Encoder) { + { + e.FieldStart("id") + e.Int64(s.ID) + } + { + e.FieldStart("method") + e.Str(s.Method) + } +} + +var jsonFieldsNameOfMethod = [2]string{ + 0: "id", + 1: "method", +} + +// Decode decodes Method from json. +func (s *Method) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Method to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "id": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Int64() + s.ID = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"id\"") + } + case "method": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Str() + s.Method = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"method\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Method") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfMethod) { + name = jsonFieldsNameOfMethod[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Method) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Method) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s *MethodExecutionResult) Encode(e *jx.Encoder) { e.ObjStart() @@ -29428,39 +29445,6 @@ func (s *OptBlockCurrencyCollection) UnmarshalJSON(data []byte) error { return s.Decode(d) } -// Encode encodes BlockchainAccountInspectCompiler as json. -func (o OptBlockchainAccountInspectCompiler) Encode(e *jx.Encoder) { - if !o.Set { - return - } - e.Str(string(o.Value)) -} - -// Decode decodes BlockchainAccountInspectCompiler from json. -func (o *OptBlockchainAccountInspectCompiler) Decode(d *jx.Decoder) error { - if o == nil { - return errors.New("invalid: unable to decode OptBlockchainAccountInspectCompiler to nil") - } - o.Set = true - if err := o.Value.Decode(d); err != nil { - return err - } - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s OptBlockchainAccountInspectCompiler) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *OptBlockchainAccountInspectCompiler) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - // Encode encodes BlockchainConfig10 as json. func (o OptBlockchainConfig10) Encode(e *jx.Encoder) { if !o.Set { @@ -35656,6 +35640,276 @@ func (s *SmartContractAction) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s *Source) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Source) encodeFields(e *jx.Encoder) { + { + e.FieldStart("files") + e.ArrStart() + for _, elem := range s.Files { + elem.Encode(e) + } + e.ArrEnd() + } +} + +var jsonFieldsNameOfSource = [1]string{ + 0: "files", +} + +// Decode decodes Source from json. +func (s *Source) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Source to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "files": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + s.Files = make([]SourceFile, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem SourceFile + if err := elem.Decode(d); err != nil { + return err + } + s.Files = append(s.Files, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"files\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Source") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfSource) { + name = jsonFieldsNameOfSource[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Source) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Source) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *SourceFile) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *SourceFile) encodeFields(e *jx.Encoder) { + { + e.FieldStart("name") + e.Str(s.Name) + } + { + e.FieldStart("content") + e.Str(s.Content) + } + { + e.FieldStart("is_entrypoint") + e.Bool(s.IsEntrypoint) + } + { + e.FieldStart("is_std_lib") + e.Bool(s.IsStdLib) + } + { + e.FieldStart("include_in_command") + e.Bool(s.IncludeInCommand) + } +} + +var jsonFieldsNameOfSourceFile = [5]string{ + 0: "name", + 1: "content", + 2: "is_entrypoint", + 3: "is_std_lib", + 4: "include_in_command", +} + +// Decode decodes SourceFile from json. +func (s *SourceFile) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode SourceFile to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "name": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.Name = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"name\"") + } + case "content": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Str() + s.Content = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"content\"") + } + case "is_entrypoint": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Bool() + s.IsEntrypoint = bool(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"is_entrypoint\"") + } + case "is_std_lib": + requiredBitSet[0] |= 1 << 3 + if err := func() error { + v, err := d.Bool() + s.IsStdLib = bool(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"is_std_lib\"") + } + case "include_in_command": + requiredBitSet[0] |= 1 << 4 + if err := func() error { + v, err := d.Bool() + s.IncludeInCommand = bool(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"include_in_command\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode SourceFile") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00011111, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfSourceFile) { + name = jsonFieldsNameOfSourceFile[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *SourceFile) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *SourceFile) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s *StateInit) Encode(e *jx.Encoder) { e.ObjStart() diff --git a/pkg/oas/oas_schemas_gen.go b/pkg/oas/oas_schemas_gen.go index d12b2ebe..47e7645e 100644 --- a/pkg/oas/oas_schemas_gen.go +++ b/pkg/oas/oas_schemas_gen.go @@ -1942,10 +1942,11 @@ func (s *BlockValueFlow) SetMinted(val BlockCurrencyCollection) { // Ref: #/components/schemas/BlockchainAccountInspect type BlockchainAccountInspect struct { - Code string `json:"code"` - CodeHash string `json:"code_hash"` - Methods []BlockchainAccountInspectMethodsItem `json:"methods"` - Compiler OptBlockchainAccountInspectCompiler `json:"compiler"` + Code string `json:"code"` + CodeHash string `json:"code_hash"` + Methods []Method `json:"methods"` + Compiler BlockchainAccountInspectCompiler `json:"compiler"` + Source Source `json:"source"` } // GetCode returns the value of Code. @@ -1959,15 +1960,20 @@ func (s *BlockchainAccountInspect) GetCodeHash() string { } // GetMethods returns the value of Methods. -func (s *BlockchainAccountInspect) GetMethods() []BlockchainAccountInspectMethodsItem { +func (s *BlockchainAccountInspect) GetMethods() []Method { return s.Methods } // GetCompiler returns the value of Compiler. -func (s *BlockchainAccountInspect) GetCompiler() OptBlockchainAccountInspectCompiler { +func (s *BlockchainAccountInspect) GetCompiler() BlockchainAccountInspectCompiler { return s.Compiler } +// GetSource returns the value of Source. +func (s *BlockchainAccountInspect) GetSource() Source { + return s.Source +} + // SetCode sets the value of Code. func (s *BlockchainAccountInspect) SetCode(val string) { s.Code = val @@ -1979,25 +1985,34 @@ func (s *BlockchainAccountInspect) SetCodeHash(val string) { } // SetMethods sets the value of Methods. -func (s *BlockchainAccountInspect) SetMethods(val []BlockchainAccountInspectMethodsItem) { +func (s *BlockchainAccountInspect) SetMethods(val []Method) { s.Methods = val } // SetCompiler sets the value of Compiler. -func (s *BlockchainAccountInspect) SetCompiler(val OptBlockchainAccountInspectCompiler) { +func (s *BlockchainAccountInspect) SetCompiler(val BlockchainAccountInspectCompiler) { s.Compiler = val } +// SetSource sets the value of Source. +func (s *BlockchainAccountInspect) SetSource(val Source) { + s.Source = val +} + type BlockchainAccountInspectCompiler string const ( BlockchainAccountInspectCompilerFunc BlockchainAccountInspectCompiler = "func" + BlockchainAccountInspectCompilerFift BlockchainAccountInspectCompiler = "fift" + BlockchainAccountInspectCompilerTact BlockchainAccountInspectCompiler = "tact" ) // AllValues returns all BlockchainAccountInspectCompiler values. func (BlockchainAccountInspectCompiler) AllValues() []BlockchainAccountInspectCompiler { return []BlockchainAccountInspectCompiler{ BlockchainAccountInspectCompilerFunc, + BlockchainAccountInspectCompilerFift, + BlockchainAccountInspectCompilerTact, } } @@ -2006,6 +2021,10 @@ func (s BlockchainAccountInspectCompiler) MarshalText() ([]byte, error) { switch s { case BlockchainAccountInspectCompilerFunc: return []byte(s), nil + case BlockchainAccountInspectCompilerFift: + return []byte(s), nil + case BlockchainAccountInspectCompilerTact: + return []byte(s), nil default: return nil, errors.Errorf("invalid value: %q", s) } @@ -2017,36 +2036,17 @@ func (s *BlockchainAccountInspectCompiler) UnmarshalText(data []byte) error { case BlockchainAccountInspectCompilerFunc: *s = BlockchainAccountInspectCompilerFunc return nil + case BlockchainAccountInspectCompilerFift: + *s = BlockchainAccountInspectCompilerFift + return nil + case BlockchainAccountInspectCompilerTact: + *s = BlockchainAccountInspectCompilerTact + return nil default: return errors.Errorf("invalid value: %q", data) } } -type BlockchainAccountInspectMethodsItem struct { - ID int64 `json:"id"` - Method string `json:"method"` -} - -// GetID returns the value of ID. -func (s *BlockchainAccountInspectMethodsItem) GetID() int64 { - return s.ID -} - -// GetMethod returns the value of Method. -func (s *BlockchainAccountInspectMethodsItem) GetMethod() string { - return s.Method -} - -// SetID sets the value of ID. -func (s *BlockchainAccountInspectMethodsItem) SetID(val int64) { - s.ID = val -} - -// SetMethod sets the value of Method. -func (s *BlockchainAccountInspectMethodsItem) SetMethod(val string) { - s.Method = val -} - // Ref: #/components/schemas/BlockchainBlock type BlockchainBlock struct { TxQuantity int `json:"tx_quantity"` @@ -9020,6 +9020,32 @@ func (s *MessageMsgType) UnmarshalText(data []byte) error { } } +// Ref: #/components/schemas/Method +type Method struct { + ID int64 `json:"id"` + Method string `json:"method"` +} + +// GetID returns the value of ID. +func (s *Method) GetID() int64 { + return s.ID +} + +// GetMethod returns the value of Method. +func (s *Method) GetMethod() string { + return s.Method +} + +// SetID sets the value of ID. +func (s *Method) SetID(val int64) { + s.ID = val +} + +// SetMethod sets the value of Method. +func (s *Method) SetMethod(val string) { + s.Method = val +} + // Ref: #/components/schemas/MethodExecutionResult type MethodExecutionResult struct { Success bool `json:"success"` @@ -10239,52 +10265,6 @@ func (o OptBlockCurrencyCollection) Or(d BlockCurrencyCollection) BlockCurrencyC return d } -// NewOptBlockchainAccountInspectCompiler returns new OptBlockchainAccountInspectCompiler with value set to v. -func NewOptBlockchainAccountInspectCompiler(v BlockchainAccountInspectCompiler) OptBlockchainAccountInspectCompiler { - return OptBlockchainAccountInspectCompiler{ - Value: v, - Set: true, - } -} - -// OptBlockchainAccountInspectCompiler is optional BlockchainAccountInspectCompiler. -type OptBlockchainAccountInspectCompiler struct { - Value BlockchainAccountInspectCompiler - Set bool -} - -// IsSet returns true if OptBlockchainAccountInspectCompiler was set. -func (o OptBlockchainAccountInspectCompiler) IsSet() bool { return o.Set } - -// Reset unsets value. -func (o *OptBlockchainAccountInspectCompiler) Reset() { - var v BlockchainAccountInspectCompiler - o.Value = v - o.Set = false -} - -// SetTo sets value to v. -func (o *OptBlockchainAccountInspectCompiler) SetTo(v BlockchainAccountInspectCompiler) { - o.Set = true - o.Value = v -} - -// Get returns value and boolean that denotes whether value was set. -func (o OptBlockchainAccountInspectCompiler) Get() (v BlockchainAccountInspectCompiler, ok bool) { - if !o.Set { - return v, false - } - return o.Value, true -} - -// Or returns value if set, or given parameter if does not. -func (o OptBlockchainAccountInspectCompiler) Or(d BlockchainAccountInspectCompiler) BlockchainAccountInspectCompiler { - if v, ok := o.Get(); ok { - return v - } - return d -} - // NewOptBlockchainConfig10 returns new OptBlockchainConfig10 with value set to v. func NewOptBlockchainConfig10(v BlockchainConfig10) OptBlockchainConfig10 { return OptBlockchainConfig10{ @@ -15605,6 +15585,80 @@ func (s *SmartContractAction) SetRefund(val OptRefund) { s.Refund = val } +// Ref: #/components/schemas/Source +type Source struct { + Files []SourceFile `json:"files"` +} + +// GetFiles returns the value of Files. +func (s *Source) GetFiles() []SourceFile { + return s.Files +} + +// SetFiles sets the value of Files. +func (s *Source) SetFiles(val []SourceFile) { + s.Files = val +} + +// Ref: #/components/schemas/SourceFile +type SourceFile struct { + Name string `json:"name"` + Content string `json:"content"` + IsEntrypoint bool `json:"is_entrypoint"` + IsStdLib bool `json:"is_std_lib"` + IncludeInCommand bool `json:"include_in_command"` +} + +// GetName returns the value of Name. +func (s *SourceFile) GetName() string { + return s.Name +} + +// GetContent returns the value of Content. +func (s *SourceFile) GetContent() string { + return s.Content +} + +// GetIsEntrypoint returns the value of IsEntrypoint. +func (s *SourceFile) GetIsEntrypoint() bool { + return s.IsEntrypoint +} + +// GetIsStdLib returns the value of IsStdLib. +func (s *SourceFile) GetIsStdLib() bool { + return s.IsStdLib +} + +// GetIncludeInCommand returns the value of IncludeInCommand. +func (s *SourceFile) GetIncludeInCommand() bool { + return s.IncludeInCommand +} + +// SetName sets the value of Name. +func (s *SourceFile) SetName(val string) { + s.Name = val +} + +// SetContent sets the value of Content. +func (s *SourceFile) SetContent(val string) { + s.Content = val +} + +// SetIsEntrypoint sets the value of IsEntrypoint. +func (s *SourceFile) SetIsEntrypoint(val bool) { + s.IsEntrypoint = val +} + +// SetIsStdLib sets the value of IsStdLib. +func (s *SourceFile) SetIsStdLib(val bool) { + s.IsStdLib = val +} + +// SetIncludeInCommand sets the value of IncludeInCommand. +func (s *SourceFile) SetIncludeInCommand(val bool) { + s.IncludeInCommand = val +} + // Ref: #/components/schemas/StateInit type StateInit struct { Boc string `json:"boc"` diff --git a/pkg/oas/oas_validators_gen.go b/pkg/oas/oas_validators_gen.go index 0ad09224..7aaedc97 100644 --- a/pkg/oas/oas_validators_gen.go +++ b/pkg/oas/oas_validators_gen.go @@ -898,15 +898,8 @@ func (s *BlockchainAccountInspect) Validate() error { }) } if err := func() error { - if value, ok := s.Compiler.Get(); ok { - if err := func() error { - if err := value.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return err - } + if err := s.Compiler.Validate(); err != nil { + return err } return nil }(); err != nil { @@ -915,6 +908,17 @@ func (s *BlockchainAccountInspect) Validate() error { Error: err, }) } + if err := func() error { + if err := s.Source.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "source", + Error: err, + }) + } if len(failures) > 0 { return &validate.Error{Fields: failures} } @@ -925,6 +929,10 @@ func (s BlockchainAccountInspectCompiler) Validate() error { switch s { case "func": return nil + case "fift": + return nil + case "tact": + return nil default: return errors.Errorf("invalid value: %v", s) } @@ -4514,6 +4522,29 @@ func (s *SmartContractAction) Validate() error { return nil } +func (s *Source) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if s.Files == nil { + return errors.New("nil is invalid value") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "files", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + func (s *StateInit) Validate() error { if s == nil { return validate.ErrNilPointer diff --git a/pkg/verifier/verifier.go b/pkg/verifier/verifier.go new file mode 100644 index 00000000..8e9b1ca8 --- /dev/null +++ b/pkg/verifier/verifier.go @@ -0,0 +1,38 @@ +package verifier + +import ( + "github.com/tonkeeper/tongo/ton" +) + +type SourceCompiler string + +const ( + SourceCompilerFunc SourceCompiler = "func" + SourceCompilerFift SourceCompiler = "fift" + SourceCompilerTact SourceCompiler = "tact" +) + +type File struct { + Name string `json:"name"` + Content string `json:"content"` + IsEntrypoint bool `json:"is_entrypoint"` + IsStdLib bool `json:"is_std_lib"` + IncludeInCommand bool `json:"include_in_command"` +} + +type Source struct { + Code string `json:"code"` + Files []File `json:"files"` + Compiler SourceCompiler `json:"compiler"` + DateVerification int64 `json:"date_verification"` +} + +type Verifier struct{} + +func NewVerifier() *Verifier { + return &Verifier{} +} + +func (v *Verifier) GetAccountSource(accountID ton.AccountID) (Source, error) { + return Source{}, nil +}