contract

package
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 10, 2024 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Command = &cli.Command{
	Name:  "contract",
	Usage: "Manages contract interfaces in the database",

	Subcommands: cli.Commands{
		{
			Name:  "addInterfaces",
			Usage: "Adds contract interface",

			ArgsUsage: "[file1.json] [file2.json]",

			Flags: []cli.Flag{
				&cli.BoolFlag{
					Name:    "stdin",
					Usage:   "read from stdin instead of files",
					Aliases: []string{"i"},
				},
			},

			Action: func(ctx *cli.Context) (err error) {
				var interfacesDesc []*abi.InterfaceDesc

				if ctx.Bool("stdin") {
					interfacesDesc, err = readStdin()
				} else {
					filenames := ctx.Args().Slice()
					if len(filenames) == 0 {
						cli.ShowSubcommandHelpAndExit(ctx, 1)
					}
					interfacesDesc, err = readFiles(filenames)
				}
				if err != nil {
					return err
				}

				definitions, interfaces, operations, err := ParseInterfacesDesc(interfacesDesc)
				if err != nil {
					return err
				}

				pg, err := dbConnect()
				if err != nil {
					return err
				}

				contractRepo := contract.NewRepository(pg)
				rescanRepo := rescan.NewRepository(pg)

				addedDef, changedDef, err := diffDefinitions(ctx.Context, contractRepo, definitions)
				if err != nil {
					return err
				}
				for dn, d := range changedDef {
					if err := contractRepo.UpdateDefinition(ctx.Context, dn, d); err != nil {
						return errors.Wrapf(err, "cannot update contract definition '%s'", dn)
					}
				}
				for dn, d := range addedDef {
					if err := contractRepo.AddDefinition(ctx.Context, dn, d); err != nil {
						return errors.Wrapf(err, "cannot insert contract definition '%s'", dn)
					}
				}

				for _, i := range interfaces {
					if err := contractRepo.AddInterface(ctx.Context, i); err != nil {
						log.Error().Err(err).Str("interface_name", string(i.Name)).Msg("cannot insert contract interface")
						continue
					}
					err := rescanInterface(ctx.Context, i.Name, rescanRepo, core.AddInterface)
					if err != nil {
						log.Error().Err(err).Str("interface_name", string(i.Name)).Msg("cannot add interface rescan task")
					}
				}

				for _, op := range operations {
					if err := contractRepo.AddOperation(ctx.Context, op); err != nil {
						log.Error().Err(err).
							Str("interface_name", string(op.ContractName)).
							Str("operation_name", op.OperationName).
							Msg("cannot insert contract operation")
						continue
					}
					err := rescanOperation(ctx.Context, rescanRepo, core.UpdOperation, op)
					if err != nil {
						log.Error().Err(err).
							Str("interface_name", string(op.ContractName)).
							Str("op_name", op.OperationName).
							Msg("cannot add operation rescan task")
					}
				}

				return nil
			},
		},
		{
			Name:  "updateInterface",
			Usage: "Updates contract interface in the database and adds rescan tasks for the difference between old and new interfaces",

			ArgsUsage: "[file1.json] [file2.json]",

			Flags: []cli.Flag{
				&cli.BoolFlag{
					Name:    "stdin",
					Usage:   "read from stdin instead of files",
					Aliases: []string{"i"},
				},
				&cli.StringFlag{
					Name:     "contract-name",
					Usage:    "contract interface for update",
					Aliases:  []string{"c"},
					Required: true,
				},
			},

			Action: func(ctx *cli.Context) (err error) {
				var interfacesDesc []*abi.InterfaceDesc

				if ctx.Bool("stdin") {
					interfacesDesc, err = readStdin()
				} else {
					filenames := ctx.Args().Slice()
					if len(filenames) == 0 {
						cli.ShowSubcommandHelpAndExit(ctx, 1)
					}
					interfacesDesc, err = readFiles(filenames)
				}
				if err != nil {
					return err
				}

				definitions, interfaces, _, err := ParseInterfacesDesc(interfacesDesc)
				if err != nil {
					return err
				}

				contractName := abi.ContractName(ctx.String("contract-name"))
				if contractName == "" {
					return errors.Wrap(core.ErrInvalidArg, "contract interface name is not set")
				}

				var newInterface *core.ContractInterface
				for _, i := range interfaces {
					if i.Name == contractName {
						newInterface = i
					}
				}
				if newInterface == nil {
					return errors.Wrapf(core.ErrInvalidArg, "contract interface '%s' is found in abi description", contractName)
				}

				pg, err := dbConnect()
				if err != nil {
					return err
				}

				contractRepo := contract.NewRepository(pg)
				rescanRepo := rescan.NewRepository(pg)

				oldInterface, err := contractRepo.GetInterface(ctx.Context, contractName)
				if err != nil {
					return errors.Wrapf(err, "get '%s' interface", newInterface.Name)
				}

				addedDef, changedDef, err := diffDefinitions(ctx.Context, contractRepo, definitions)
				if err != nil {
					return err
				}
				for dn, d := range changedDef {
					if err := contractRepo.UpdateDefinition(ctx.Context, dn, d); err != nil {
						return errors.Wrapf(err, "cannot update contract definition '%s'", dn)
					}
				}
				for dn, d := range addedDef {
					if err := contractRepo.AddDefinition(ctx.Context, dn, d); err != nil {
						return errors.Wrapf(err, "cannot insert contract definition '%s'", dn)
					}
				}

				iChanged, addedGm, changedGm, deletedGm := diffInterface(oldInterface, newInterface)
				if iChanged || len(addedGm) > 0 || len(changedGm) > 0 || len(deletedGm) > 0 {
					if err := contractRepo.UpdateInterface(ctx.Context, newInterface); err != nil {
						return errors.Wrapf(err, "cannot update contract interface '%s'", newInterface.Name)
					}
				}

				addedOp, changedOp, deletedOp := diffOperations(oldInterface.Operations, newInterface.Operations)
				for _, op := range deletedOp {
					if err := contractRepo.DeleteOperation(ctx.Context, op.OperationName); err != nil {
						return errors.Wrapf(err, "cannot delete contract operation '%s'", op.OperationName)
					}
				}
				for _, op := range changedOp {
					if err := contractRepo.UpdateOperation(ctx.Context, op); err != nil {
						return errors.Wrapf(err, "cannot update contract operation '%s'", op.OperationName)
					}
				}
				for _, op := range addedOp {
					if err := contractRepo.AddOperation(ctx.Context, op); err != nil {
						return errors.Wrapf(err, "cannot insert contract operation '%s'", op.OperationName)
					}
				}

				if iChanged {
					if err := rescanInterface(ctx.Context, contractName, rescanRepo, core.UpdInterface); err != nil {
						return err
					}
				}

				if err := rescanGetMethod(ctx.Context, contractName, rescanRepo, core.AddGetMethod, getGetMethodNames(addedGm)); err != nil {
					return err
				}
				if err := rescanGetMethod(ctx.Context, contractName, rescanRepo, core.UpdGetMethod, getGetMethodNames(changedGm)); err != nil {
					return err
				}
				if err := rescanGetMethod(ctx.Context, contractName, rescanRepo, core.DelGetMethod, getGetMethodNames(deletedGm)); err != nil {
					return err
				}

				for _, op := range deletedOp {
					if err := rescanOperation(ctx.Context, rescanRepo, core.DelOperation, op); err != nil {
						return err
					}
				}
				for _, op := range append(addedOp, changedOp...) {
					if err := rescanOperation(ctx.Context, rescanRepo, core.UpdOperation, op); err != nil {
						return err
					}
				}

				return nil
			},
		},
		{
			Name:  "deleteInterface",
			Usage: "Deletes contract interface from the database and removes associated parsed data",

			Flags: []cli.Flag{
				&cli.StringFlag{
					Name:     "contract-name",
					Usage:    "contract interface for deletion",
					Aliases:  []string{"c"},
					Required: true,
				},
			},

			Action: func(ctx *cli.Context) (err error) {
				contractName := abi.ContractName(ctx.String("contract-name"))
				if contractName == "" {
					return errors.Wrap(core.ErrInvalidArg, "contract interface name is not set")
				}

				pg, err := dbConnect()
				if err != nil {
					return err
				}

				contractRepo := contract.NewRepository(pg)
				rescanRepo := rescan.NewRepository(pg)

				oldInterface, err := contractRepo.GetInterface(ctx.Context, contractName)
				if err != nil {
					return errors.Wrapf(err, "get '%s' interface", contractName)
				}

				if err := contractRepo.DeleteInterface(ctx.Context, contractName); err != nil {
					return errors.Wrapf(err, "cannot delete '%s' interface", contractName)
				}

				for _, op := range oldInterface.Operations {
					if err := rescanOperation(ctx.Context, rescanRepo, core.DelOperation, op); err != nil {
						return err
					}
				}

				err = rescanInterface(ctx.Context, contractName, rescanRepo, core.DelInterface)
				if err != nil {
					return err
				}

				return nil
			},
		},
	},
}

Functions

func ParseInterfaceDesc added in v0.4.1

func ParseInterfaceDesc(d *abi.InterfaceDesc) (*core.ContractInterface, []*core.ContractOperation, error)

func ParseInterfacesDesc added in v0.4.1

func ParseInterfacesDesc(descriptors []*abi.InterfaceDesc) (retD map[abi.TLBType]abi.TLBFieldsDesc, retI []*core.ContractInterface, retOp []*core.ContractOperation, _ error)

func ParseOperationDesc added in v0.4.1

func ParseOperationDesc(t abi.ContractName, d *abi.OperationDesc) (*core.ContractOperation, error)

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL